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