parent
fdcac81021
commit
01a18ef9cb
@ -0,0 +1,9 @@ |
||||
#ifndef I2C_GATEWAY_H |
||||
#define I2C_GATEWAY_H |
||||
|
||||
#include <stdint.h> |
||||
#include <stddef.h> |
||||
|
||||
void i2c_command(uint8_t *packet, size_t len); |
||||
|
||||
#endif //I2C_GATEWAY_H
|
@ -0,0 +1,181 @@ |
||||
#include <stdint.h> |
||||
#include <stdio.h> |
||||
#include "main.h" |
||||
#include "usbd_cdc_if.h" |
||||
|
||||
#define I2C_DEBUG 0 |
||||
|
||||
#define I2C_MTU 512 |
||||
|
||||
#define HAL_CHECK(x) do { \ |
||||
int rv = (x); \
|
||||
if (rv != HAL_OK) { \
|
||||
printf("HAL ERR %d at %s:%d\r\n", rv, __FILE__, __LINE__); \
|
||||
}\
|
||||
} while (0) |
||||
|
||||
/**
|
||||
* Packet format: |
||||
* |
||||
* Transmit packets |
||||
* LEN_MSB LEN_LSB ADDR Bytes... |
||||
* |
||||
* LEN does not include the length field itself! |
||||
* |
||||
* Command packets are sent as ADDR=255 |
||||
* 0xFF CMD ARGs... |
||||
* - Set address: 0x01 ADDR |
||||
* - Set speed: 0x02 Speed TODO!! |
||||
* - Speed 1 ... 100kHz |
||||
* - Speed 4 ... 400kHz |
||||
*/ |
||||
|
||||
#define COMMAND_ADDRESS 0xFF |
||||
#define CMD_SET_ADDR 1 // the next param is the address, without shifting (i.e. 1-127)
|
||||
#define CMD_SET_SPEED 2 // speed is 1 or 4 (100khz, 400khz)
|
||||
|
||||
enum FrameState { |
||||
FRAME_LEN_MSB, |
||||
FRAME_LEN_LSB, |
||||
FRAME_PAYLOAD, |
||||
}; |
||||
|
||||
static uint16_t framelen = 0; |
||||
static uint8_t i2c_recbuf[I2C_MTU + 3] = {}; |
||||
static size_t recbuf_wp = 0; |
||||
static size_t framestate = FRAME_LEN_MSB; |
||||
static uint32_t last_rx_tick; |
||||
#define CMD_TIMEOUT_TICKS 500 |
||||
|
||||
|
||||
static void handle_pkt(uint8_t *packet, size_t len); |
||||
static void handle_control_pkt(uint8_t *packet, size_t len); |
||||
|
||||
void i2c_command(uint8_t *packet, size_t len) |
||||
{ |
||||
uint32_t now = HAL_GetTick(); |
||||
if (framestate != FRAME_LEN_MSB && (now - last_rx_tick) > CMD_TIMEOUT_TICKS) { |
||||
framestate = FRAME_LEN_MSB; |
||||
} |
||||
last_rx_tick = now; |
||||
|
||||
for (int i=0; i<len;i++) { |
||||
uint8_t b = packet[i]; |
||||
switch (framestate) { |
||||
case FRAME_LEN_MSB: |
||||
framelen = ((uint16_t)b) << 8; |
||||
framestate = FRAME_LEN_LSB; |
||||
break; |
||||
case FRAME_LEN_LSB: |
||||
framelen |= (uint16_t)b; |
||||
if (framelen == 0) { |
||||
framestate = FRAME_LEN_MSB; |
||||
} else { |
||||
framestate = FRAME_PAYLOAD; |
||||
recbuf_wp = 0; |
||||
} |
||||
break; |
||||
case FRAME_PAYLOAD: |
||||
i2c_recbuf[recbuf_wp++] = b; |
||||
if (recbuf_wp >= framelen) { |
||||
handle_pkt(i2c_recbuf, framelen); |
||||
framestate = FRAME_LEN_MSB; |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
static void handle_pkt(uint8_t *packet, size_t len) |
||||
{ |
||||
#if I2C_DEBUG |
||||
printf("Handle packet (%d bytes): ", len); |
||||
for(int i=0; i<len;i++) { |
||||
printf("%02x ", packet[i]); |
||||
} |
||||
printf("\r\n"); |
||||
#endif |
||||
|
||||
if (packet[0] == COMMAND_ADDRESS) { |
||||
printf("ctl: "); |
||||
// This is an in-band control packet
|
||||
handle_control_pkt(packet, len); |
||||
} else { |
||||
uint8_t dest = packet[0]; |
||||
|
||||
#if I2C_DEBUG |
||||
printf("Tx(%d)->%d\r\n", len - 1, dest); |
||||
#endif |
||||
|
||||
// Blocking transfer
|
||||
HAL_CHECK(HAL_I2C_DisableListen_IT(&hi2c1)); |
||||
HAL_CHECK(HAL_I2C_Master_Transmit(&hi2c1, (dest & 0x7F) << 1, &packet[1], len - 1, 100)); |
||||
HAL_CHECK(HAL_I2C_EnableListen_IT(&hi2c1)); |
||||
} |
||||
} |
||||
|
||||
static void handle_control_pkt(uint8_t *packet, size_t len) |
||||
{ |
||||
uint8_t cmd = packet[1]; |
||||
uint8_t arg; |
||||
|
||||
switch (cmd) { |
||||
case CMD_SET_ADDR: |
||||
if (len < 3) return; |
||||
arg = packet[2]; |
||||
printf("Addr=0x%02x\r\n", arg); |
||||
MODIFY_REG(hi2c1.Instance->OAR1, |
||||
(I2C_OAR1_ADDMODE | I2C_OAR1_ADD8_9 | I2C_OAR1_ADD1_7 | I2C_OAR1_ADD0), |
||||
(I2C_ADDRESSINGMODE_7BIT | ((arg & 0x7F) << 1) )); |
||||
HAL_CHECK(HAL_I2C_EnableListen_IT(&hi2c1)); |
||||
break; |
||||
|
||||
default: |
||||
printf("bad cmd!\r\n"); |
||||
} |
||||
} |
||||
|
||||
/**
|
||||
* @brief Slave Address Match callback. |
||||
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains |
||||
* the configuration information for the specified I2C. |
||||
* @param TransferDirection Master request Transfer Direction (Write/Read), value of @ref I2C_XferDirection_definition |
||||
* @param AddrMatchCode Address Match Code |
||||
* @retval None |
||||
*/ |
||||
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) |
||||
{ |
||||
HAL_CHECK(HAL_I2C_Slave_Seq_Receive_IT(hi2c, i2c_recbuf, I2C_MTU, I2C_FIRST_AND_LAST_FRAME)); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Slave Rx Transfer completed callback. |
||||
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains |
||||
* the configuration information for the specified I2C. |
||||
* @retval None |
||||
*/ |
||||
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c) |
||||
{ |
||||
int numBytes = I2C_MTU - hi2c->XferCount; |
||||
#if I2C_DEBUG |
||||
printf("rxd %d\r\n", numBytes); |
||||
#endif |
||||
|
||||
UserTxBufferFS[0] = (numBytes >> 8) & 0xFF; |
||||
UserTxBufferFS[1] = numBytes & 0xFF; |
||||
memcpy(&UserTxBufferFS[2], i2c_recbuf, numBytes); |
||||
|
||||
CDC_Transmit_FS(UserTxBufferFS, numBytes + 2); |
||||
} |
||||
|
||||
/**
|
||||
* @brief Listen Complete callback. |
||||
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains |
||||
* the configuration information for the specified I2C. |
||||
* @retval None |
||||
*/ |
||||
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c) |
||||
{ |
||||
// Start again
|
||||
HAL_CHECK(HAL_I2C_EnableListen_IT(hi2c)); |
||||
} |
Loading…
Reference in new issue