i2c slave block transfer driver library

Dependents:   i2c_slave_block_example i2c_lora_slave

I2C block read/write slave

operates with I2C master using the i2c_smbus_read_i2c_block_data() and i2c_smbus_write_i2c_block_data() calls.

Tested with raspberry pi as master.
STM32Lx nucleo as slave.

signal pinmbed slaveRPi master
GND6
SCLD155
SDAD143
IRQany avail pinany avail pin

IRQ pin is implemented in application, not in this library. (see example)

Up to 32byte length per transfer.
Raspberry pi I2C doesnt support SMBUS block read, so I2C block transfers are supported here.
SMBUS block transfers are variable length. Instead, here in this driver, I2C block length is mapped to command byte by const array cmd_to_length[] (see example)

master write to slave

For i2c_smbus_write_i2c_block_data() from master, this driver lets the main loop on slave take the write request. The main loop on slave calls service_i2c(), which then calls service_i2c_write() upon each write from master. This occurs thru a circular buffer, permitting the slave to take its time doing the request, while the master can issue several back-to-back requests without delays.

clock stretching

For i2c_smbus_read_i2c_block_data(): Since raspberry pi doesnt support clock stretching out the the box, providing transmit data must be done in the interrupt service routine. fill_tx_buf() populates the transmit buffer to be sent to master, which must be done immediately because this occurs inside interrupt handler. If I2C master were to support clock stretching, then transmit buffer work could be done in main loop of slave.
/media/uploads/dudmuck/i2c_rpi_nucleo_sm_.png
An STM32 running at 32MHz is unlikely to operate with 400KHz I2C. Use 100KHz speed with 32MHz CPU, or use faster speed CPU for 400KHz I2C.

Committer:
Wayne Roberts
Date:
Mon Feb 04 13:42:05 2019 -0800
Revision:
5:493e5cc9c052
Parent:
4:7ab789db70da
update HAL state for STM32L4

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 3:c012313ebc13 1 #include "hal/pinmap.h"
Wayne Roberts 3:c012313ebc13 2 #include "PeripheralPins.h"
Wayne Roberts 3:c012313ebc13 3 #include "i2c_device.h"
Wayne Roberts 0:20421a857bd5 4 #include "smbus.h"
Wayne Roberts 3:c012313ebc13 5 #include "mbed_interface.h" // mbed_error_printf
Wayne Roberts 0:20421a857bd5 6
Wayne Roberts 0:20421a857bd5 7 i2c_slave_t i2c;
Wayne Roberts 0:20421a857bd5 8
Wayne Roberts 3:c012313ebc13 9 static DMA_HandleTypeDef hdma_tx;
Wayne Roberts 3:c012313ebc13 10 static DMA_HandleTypeDef hdma_rx;
Wayne Roberts 3:c012313ebc13 11 static SMBUS_HandleTypeDef SmbusHandle;
Wayne Roberts 3:c012313ebc13 12 static IRQn_Type event_i2cIRQ;
Wayne Roberts 3:c012313ebc13 13 static IRQn_Type error_i2cIRQ;
Wayne Roberts 3:c012313ebc13 14
Wayne Roberts 0:20421a857bd5 15 static inline void put_cbuf(uint8_t o)
Wayne Roberts 0:20421a857bd5 16 {
Wayne Roberts 0:20421a857bd5 17 i2c.cbuf[i2c.cbuf_in] = o;
Wayne Roberts 3:c012313ebc13 18 if (++i2c.cbuf_in == CBUF_SIZE)
Wayne Roberts 0:20421a857bd5 19 i2c.cbuf_in = 0;
Wayne Roberts 3:c012313ebc13 20
Wayne Roberts 3:c012313ebc13 21 if (i2c.cbuf_in == i2c.cbuf_out) {
Wayne Roberts 3:c012313ebc13 22 i2c.c_overrun = true;
Wayne Roberts 3:c012313ebc13 23 }
Wayne Roberts 0:20421a857bd5 24 }
Wayne Roberts 0:20421a857bd5 25
Wayne Roberts 3:c012313ebc13 26 static inline void err_irqHandler(uint32_t tmpisrvalue)
Wayne Roberts 3:c012313ebc13 27 {
Wayne Roberts 3:c012313ebc13 28 uint32_t _icr = 0;
Wayne Roberts 3:c012313ebc13 29 if (tmpisrvalue & SMBUS_FLAG_BERR) {
Wayne Roberts 3:c012313ebc13 30 put_cbuf(CMD_BUSERR);
Wayne Roberts 3:c012313ebc13 31 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 32 put_cbuf(hdma_tx.Instance->CNDTR); // req[0]
Wayne Roberts 3:c012313ebc13 33
Wayne Roberts 3:c012313ebc13 34 _icr |= SMBUS_FLAG_BERR;
Wayne Roberts 3:c012313ebc13 35 }
Wayne Roberts 3:c012313ebc13 36
Wayne Roberts 3:c012313ebc13 37 if (tmpisrvalue & SMBUS_FLAG_ARLO) {
Wayne Roberts 3:c012313ebc13 38 put_cbuf(CMD_ARLO);
Wayne Roberts 3:c012313ebc13 39 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 40 put_cbuf(hdma_tx.Instance->CNDTR); // req[0]
Wayne Roberts 3:c012313ebc13 41
Wayne Roberts 3:c012313ebc13 42 _icr |= SMBUS_FLAG_ARLO;
Wayne Roberts 3:c012313ebc13 43 }
Wayne Roberts 3:c012313ebc13 44
Wayne Roberts 3:c012313ebc13 45 if (tmpisrvalue & SMBUS_FLAG_TIMEOUT) {
Wayne Roberts 3:c012313ebc13 46 SmbusHandle.Instance->CR1 &= ~I2C_CR1_TXDMAEN;
Wayne Roberts 3:c012313ebc13 47 __HAL_DMA_DISABLE(&hdma_tx);
Wayne Roberts 3:c012313ebc13 48 __HAL_UNLOCK(&hdma_tx);
Wayne Roberts 5:493e5cc9c052 49 hdma_tx.State = HAL_DMA_STATE_READY;
Wayne Roberts 3:c012313ebc13 50
Wayne Roberts 3:c012313ebc13 51 SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 52 __HAL_DMA_DISABLE(&hdma_rx);
Wayne Roberts 3:c012313ebc13 53 __HAL_UNLOCK(&hdma_rx);
Wayne Roberts 5:493e5cc9c052 54 hdma_rx.State = HAL_DMA_STATE_READY;
Wayne Roberts 3:c012313ebc13 55
Wayne Roberts 3:c012313ebc13 56 put_cbuf(CMD_TIMEOUT);
Wayne Roberts 3:c012313ebc13 57 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 58 put_cbuf(hdma_tx.Instance->CNDTR); // req[0]
Wayne Roberts 5:493e5cc9c052 59
Wayne Roberts 3:c012313ebc13 60 _icr |= SMBUS_FLAG_TIMEOUT;
Wayne Roberts 3:c012313ebc13 61 }
Wayne Roberts 3:c012313ebc13 62
Wayne Roberts 3:c012313ebc13 63 __HAL_SMBUS_CLEAR_FLAG(&SmbusHandle, _icr);
Wayne Roberts 3:c012313ebc13 64 }
Wayne Roberts 0:20421a857bd5 65
Wayne Roberts 0:20421a857bd5 66 #ifdef TARGET_STM32L4
Wayne Roberts 0:20421a857bd5 67 void SMBUSx_ER_IRQHandler()
Wayne Roberts 0:20421a857bd5 68 {
Wayne Roberts 3:c012313ebc13 69 err_irqHandler(SMBUS_GET_ISR_REG(&SmbusHandle));
Wayne Roberts 0:20421a857bd5 70 }
Wayne Roberts 0:20421a857bd5 71
Wayne Roberts 0:20421a857bd5 72 void SMBUSx_EV_IRQHandler(void)
Wayne Roberts 0:20421a857bd5 73 #else
Wayne Roberts 0:20421a857bd5 74 void SMBUSx_IRQHandler(void)
Wayne Roberts 0:20421a857bd5 75 #endif
Wayne Roberts 0:20421a857bd5 76 {
Wayne Roberts 0:20421a857bd5 77 uint32_t tmpisrvalue = SMBUS_GET_ISR_REG(&SmbusHandle);
Wayne Roberts 0:20421a857bd5 78 uint32_t icr = 0;
Wayne Roberts 3:c012313ebc13 79
Wayne Roberts 0:20421a857bd5 80 static bool i2cTransferDirection; // true = read
Wayne Roberts 3:c012313ebc13 81 static bool stopWaiting = false;
Wayne Roberts 3:c012313ebc13 82
Wayne Roberts 3:c012313ebc13 83 static uint8_t _rx_buf[33]; // [0] is cmd
Wayne Roberts 0:20421a857bd5 84
Wayne Roberts 3:c012313ebc13 85 /* often multiple flags are set simultaneously, yet must still be taken in correct order */
Wayne Roberts 0:20421a857bd5 86
Wayne Roberts 3:c012313ebc13 87 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 88 put_cbuf(CMD_ISR);
Wayne Roberts 3:c012313ebc13 89 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 90 put_cbuf(tmpisrvalue & 0xff);
Wayne Roberts 3:c012313ebc13 91 #endif /* DEBUG_SMBUS */
Wayne Roberts 0:20421a857bd5 92
Wayne Roberts 0:20421a857bd5 93 if (tmpisrvalue & SMBUS_FLAG_ADDR) {
Wayne Roberts 0:20421a857bd5 94 i2cTransferDirection = SMBUS_GET_DIR(&SmbusHandle);
Wayne Roberts 3:c012313ebc13 95 if (i2cTransferDirection) { // if host read
Wayne Roberts 0:20421a857bd5 96 // 1: Read transfer, slave enters transmitter mode.. cmd has already been provided
Wayne Roberts 5:493e5cc9c052 97
Wayne Roberts 3:c012313ebc13 98 SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 99 __HAL_DMA_DISABLE(&hdma_rx);
Wayne Roberts 3:c012313ebc13 100 __HAL_UNLOCK(&hdma_rx);
Wayne Roberts 5:493e5cc9c052 101 hdma_rx.State = HAL_DMA_STATE_READY;
Wayne Roberts 5:493e5cc9c052 102 #ifdef TARGET_STM32L4
Wayne Roberts 5:493e5cc9c052 103 // clear dma interrupt flags
Wayne Roberts 5:493e5cc9c052 104 hdma_rx.DmaBaseAddress->IFCR = (DMA_ISR_GIF1 << hdma_rx.ChannelIndex);
Wayne Roberts 5:493e5cc9c052 105 #endif
Wayne Roberts 3:c012313ebc13 106
Wayne Roberts 3:c012313ebc13 107 fill_tx_buf(_rx_buf[0]);
Wayne Roberts 0:20421a857bd5 108
Wayne Roberts 3:c012313ebc13 109 #ifdef DEBUG_SMBUS
Wayne Roberts 5:493e5cc9c052 110 put_cbuf(CMD_ADDR_HOST_READ); // AHR
Wayne Roberts 3:c012313ebc13 111 put_cbuf(2);
Wayne Roberts 3:c012313ebc13 112 put_cbuf(cmd_to_length[_rx_buf[0]]);
Wayne Roberts 3:c012313ebc13 113 put_cbuf(hdma_tx.Instance->CNDTR);
Wayne Roberts 3:c012313ebc13 114 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 115 SmbusHandle.Instance->CR1 |= I2C_CR1_TXDMAEN;
Wayne Roberts 3:c012313ebc13 116 HAL_DMA_Start(&hdma_tx, (uint32_t)i2c.tx_buf, (uint32_t)&SmbusHandle.Instance->TXDR, cmd_to_length[_rx_buf[0]]);
Wayne Roberts 3:c012313ebc13 117
Wayne Roberts 3:c012313ebc13 118 icr |= SMBUS_FLAG_ADDR;
Wayne Roberts 3:c012313ebc13 119 } else if (!stopWaiting) {
Wayne Roberts 0:20421a857bd5 120 // 0: Write transfer, slave enters receiver mode.
Wayne Roberts 5:493e5cc9c052 121
Wayne Roberts 3:c012313ebc13 122 SmbusHandle.Instance->CR1 |= I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 123 HAL_DMA_Start(&hdma_rx, (uint32_t)&SmbusHandle.Instance->RXDR, (uint32_t)_rx_buf, sizeof(_rx_buf));
Wayne Roberts 3:c012313ebc13 124
Wayne Roberts 3:c012313ebc13 125 #ifdef DEBUG_SMBUS
Wayne Roberts 5:493e5cc9c052 126 put_cbuf(CMD_ADDR_HOST_WRITE); // AHW
Wayne Roberts 3:c012313ebc13 127 put_cbuf(1);
Wayne Roberts 5:493e5cc9c052 128 put_cbuf(hdma_rx.Instance->CNDTR);
Wayne Roberts 3:c012313ebc13 129 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 130
Wayne Roberts 3:c012313ebc13 131 icr |= SMBUS_FLAG_ADDR;
Wayne Roberts 0:20421a857bd5 132 }
Wayne Roberts 0:20421a857bd5 133
Wayne Roberts 3:c012313ebc13 134 stopWaiting = true;
Wayne Roberts 0:20421a857bd5 135 }
Wayne Roberts 0:20421a857bd5 136
Wayne Roberts 3:c012313ebc13 137 #ifdef TARGET_STM32L0
Wayne Roberts 3:c012313ebc13 138 err_irqHandler(tmpisrvalue);
Wayne Roberts 3:c012313ebc13 139 #endif
Wayne Roberts 3:c012313ebc13 140
Wayne Roberts 0:20421a857bd5 141 if (tmpisrvalue & SMBUS_FLAG_AF) {
Wayne Roberts 0:20421a857bd5 142 /* last byte the host wants was sent */
Wayne Roberts 3:c012313ebc13 143 SmbusHandle.Instance->CR1 &= ~I2C_CR1_TXDMAEN;
Wayne Roberts 3:c012313ebc13 144 __HAL_DMA_DISABLE(&hdma_tx);
Wayne Roberts 3:c012313ebc13 145 __HAL_UNLOCK(&hdma_tx);
Wayne Roberts 5:493e5cc9c052 146 hdma_tx.State = HAL_DMA_STATE_READY;
Wayne Roberts 3:c012313ebc13 147
Wayne Roberts 3:c012313ebc13 148 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 149 put_cbuf(CMD_AF);
Wayne Roberts 3:c012313ebc13 150 put_cbuf(1);
Wayne Roberts 3:c012313ebc13 151 put_cbuf(hdma_tx.Instance->CNDTR);
Wayne Roberts 3:c012313ebc13 152 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 153
Wayne Roberts 0:20421a857bd5 154 icr |= SMBUS_FLAG_AF;
Wayne Roberts 0:20421a857bd5 155 }
Wayne Roberts 0:20421a857bd5 156
Wayne Roberts 0:20421a857bd5 157 if (tmpisrvalue & SMBUS_FLAG_STOPF) {
Wayne Roberts 3:c012313ebc13 158 #ifdef DEBUG_SMBUS
Wayne Roberts 3:c012313ebc13 159 put_cbuf(CMD_STOPF);
Wayne Roberts 3:c012313ebc13 160 put_cbuf(0);
Wayne Roberts 3:c012313ebc13 161 #endif /* DEBUG_SMBUS */
Wayne Roberts 3:c012313ebc13 162
Wayne Roberts 0:20421a857bd5 163 icr |= SMBUS_FLAG_STOPF;
Wayne Roberts 3:c012313ebc13 164 if (i2cTransferDirection == 0) {
Wayne Roberts 3:c012313ebc13 165 /* host done writing to buf */
Wayne Roberts 3:c012313ebc13 166 unsigned i, len;
Wayne Roberts 3:c012313ebc13 167
Wayne Roberts 3:c012313ebc13 168 SmbusHandle.Instance->CR1 &= ~I2C_CR1_RXDMAEN;
Wayne Roberts 3:c012313ebc13 169 __HAL_DMA_DISABLE(&hdma_rx);
Wayne Roberts 3:c012313ebc13 170 __HAL_UNLOCK(&hdma_rx);
Wayne Roberts 5:493e5cc9c052 171 hdma_rx.State = HAL_DMA_STATE_READY;
Wayne Roberts 3:c012313ebc13 172
Wayne Roberts 3:c012313ebc13 173 len = sizeof(_rx_buf) - hdma_rx.Instance->CNDTR;
Wayne Roberts 3:c012313ebc13 174 if (len > 0) {
Wayne Roberts 3:c012313ebc13 175 /* send to mainloop */
Wayne Roberts 3:c012313ebc13 176 put_cbuf(_rx_buf[0]);
Wayne Roberts 3:c012313ebc13 177 put_cbuf(len-1);
Wayne Roberts 3:c012313ebc13 178 for (i = 1; i < len; i++)
Wayne Roberts 3:c012313ebc13 179 put_cbuf(_rx_buf[i]);
Wayne Roberts 3:c012313ebc13 180 }
Wayne Roberts 0:20421a857bd5 181 }
Wayne Roberts 0:20421a857bd5 182
Wayne Roberts 0:20421a857bd5 183 if (!(tmpisrvalue & SMBUS_FLAG_TXE)) {
Wayne Roberts 0:20421a857bd5 184 /* slave wanted to send more than host wanted to receive */
Wayne Roberts 0:20421a857bd5 185 SmbusHandle.Instance->ISR = SMBUS_FLAG_TXE;
Wayne Roberts 0:20421a857bd5 186 }
Wayne Roberts 0:20421a857bd5 187
Wayne Roberts 3:c012313ebc13 188 stopWaiting = false;
Wayne Roberts 3:c012313ebc13 189 } // ..if (tmpisrvalue & SMBUS_FLAG_STOPF)
Wayne Roberts 0:20421a857bd5 190
Wayne Roberts 0:20421a857bd5 191 __HAL_SMBUS_CLEAR_FLAG(&SmbusHandle, icr);
Wayne Roberts 0:20421a857bd5 192 }
Wayne Roberts 0:20421a857bd5 193
Wayne Roberts 3:c012313ebc13 194 #define I2C_TIMING 0x10900CD6
Wayne Roberts 3:c012313ebc13 195
Wayne Roberts 3:c012313ebc13 196 int smbus_init( PinName sda, PinName scl, uint8_t slaveAddress)
Wayne Roberts 0:20421a857bd5 197 {
Wayne Roberts 3:c012313ebc13 198 DMA_Channel_TypeDef *dma_ch_tx, *dma_ch_rx;
Wayne Roberts 3:c012313ebc13 199 uint32_t dma_req_tx, dma_req_rx;
Wayne Roberts 3:c012313ebc13 200 RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct;
Wayne Roberts 0:20421a857bd5 201 uint32_t tmpisr;
Wayne Roberts 3:c012313ebc13 202 I2CName i2c;
Wayne Roberts 3:c012313ebc13 203
Wayne Roberts 3:c012313ebc13 204 I2CName i2c_sda = (I2CName)pinmap_peripheral(sda, PinMap_I2C_SDA);
Wayne Roberts 3:c012313ebc13 205 I2CName i2c_scl = (I2CName)pinmap_peripheral(scl, PinMap_I2C_SCL);
Wayne Roberts 3:c012313ebc13 206
Wayne Roberts 3:c012313ebc13 207 // Configure I2C pins
Wayne Roberts 3:c012313ebc13 208 pinmap_pinout(sda, PinMap_I2C_SDA);
Wayne Roberts 3:c012313ebc13 209 pinmap_pinout(scl, PinMap_I2C_SCL);
Wayne Roberts 3:c012313ebc13 210 pin_mode(sda, OpenDrainNoPull);
Wayne Roberts 3:c012313ebc13 211 pin_mode(scl, OpenDrainNoPull);
Wayne Roberts 3:c012313ebc13 212
Wayne Roberts 3:c012313ebc13 213 i2c = (I2CName)pinmap_merge(i2c_sda, i2c_scl);;
Wayne Roberts 3:c012313ebc13 214
Wayne Roberts 3:c012313ebc13 215 if (i2c == I2C_1) {
Wayne Roberts 3:c012313ebc13 216 SmbusHandle.Instance = I2C1;
Wayne Roberts 3:c012313ebc13 217 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C1;
Wayne Roberts 3:c012313ebc13 218 RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C1CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 219 __HAL_RCC_I2C1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 220 event_i2cIRQ = I2C1_EV_IRQn;
Wayne Roberts 3:c012313ebc13 221 error_i2cIRQ = I2C1_ER_IRQn;
Wayne Roberts 3:c012313ebc13 222
Wayne Roberts 3:c012313ebc13 223 __HAL_RCC_DMA1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 224 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 225 dma_ch_tx = DMA1_Channel6;
Wayne Roberts 3:c012313ebc13 226 dma_ch_rx = DMA1_Channel7;
Wayne Roberts 3:c012313ebc13 227 dma_req_tx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 228 dma_req_rx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 229 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 230 dma_ch_tx = DMA1_Channel6;
Wayne Roberts 3:c012313ebc13 231 dma_ch_rx = DMA1_Channel7;
Wayne Roberts 3:c012313ebc13 232 dma_req_tx = DMA_REQUEST_6;
Wayne Roberts 3:c012313ebc13 233 dma_req_rx = DMA_REQUEST_6;
Wayne Roberts 3:c012313ebc13 234 #endif
Wayne Roberts 3:c012313ebc13 235 }
Wayne Roberts 3:c012313ebc13 236 #if defined I2C2_BASE
Wayne Roberts 3:c012313ebc13 237 else if (i2c == I2C_2) {
Wayne Roberts 3:c012313ebc13 238 SmbusHandle.Instance = I2C2;
Wayne Roberts 3:c012313ebc13 239 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C2;
Wayne Roberts 3:c012313ebc13 240 #ifdef RCC_I2C2CLKSOURCE_SYSCLK
Wayne Roberts 3:c012313ebc13 241 RCC_PeriphCLKInitStruct.I2c1ClockSelection = RCC_I2C2CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 242 #endif /* RCC_I2C2CLKSOURCE_SYSCLK */
Wayne Roberts 3:c012313ebc13 243 __HAL_RCC_I2C2_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 244 event_i2cIRQ = I2C2_EV_IRQn;
Wayne Roberts 3:c012313ebc13 245 error_i2cIRQ = I2C2_ER_IRQn;
Wayne Roberts 0:20421a857bd5 246
Wayne Roberts 3:c012313ebc13 247 __HAL_RCC_DMA1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 248 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 249 dma_ch_tx = DMA1_Channel4;
Wayne Roberts 3:c012313ebc13 250 dma_ch_rx = DMA1_Channel5;
Wayne Roberts 3:c012313ebc13 251 dma_req_tx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 252 dma_req_rx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 253 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 254 dma_ch_tx = DMA1_Channel4;
Wayne Roberts 3:c012313ebc13 255 dma_ch_rx = DMA1_Channel5;
Wayne Roberts 3:c012313ebc13 256 dma_req_tx = DMA_REQUEST_7;
Wayne Roberts 3:c012313ebc13 257 dma_req_rx = DMA_REQUEST_7;
Wayne Roberts 3:c012313ebc13 258 #endif
Wayne Roberts 3:c012313ebc13 259 }
Wayne Roberts 3:c012313ebc13 260 #endif /* I2C2_BASE */
Wayne Roberts 3:c012313ebc13 261 #if defined I2C3_BASE
Wayne Roberts 3:c012313ebc13 262 else if (i2c == I2C_3) {
Wayne Roberts 3:c012313ebc13 263 SmbusHandle.Instance = I2C3;
Wayne Roberts 3:c012313ebc13 264 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C3;
Wayne Roberts 3:c012313ebc13 265 RCC_PeriphCLKInitStruct.I2c3ClockSelection = RCC_I2C3CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 266 __HAL_RCC_I2C3_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 267 event_i2cIRQ = I2C3_EV_IRQn;
Wayne Roberts 3:c012313ebc13 268 error_i2cIRQ = I2C3_ER_IRQn;
Wayne Roberts 0:20421a857bd5 269
Wayne Roberts 3:c012313ebc13 270 __HAL_RCC_DMA1_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 271 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 272 dma_ch_tx = DMA1_Channel2;
Wayne Roberts 3:c012313ebc13 273 dma_ch_rx = DMA1_Channel3;
Wayne Roberts 3:c012313ebc13 274 dma_req_tx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 275 dma_req_rx = DMA_REQUEST_3;
Wayne Roberts 3:c012313ebc13 276 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 277 dma_ch_tx = DMA1_Channel4;
Wayne Roberts 3:c012313ebc13 278 dma_ch_rx = DMA1_Channel5;
Wayne Roberts 3:c012313ebc13 279 dma_req_tx = DMA_REQUEST_14;
Wayne Roberts 3:c012313ebc13 280 dma_req_rx = DMA_REQUEST_14;
Wayne Roberts 3:c012313ebc13 281 #endif
Wayne Roberts 3:c012313ebc13 282 }
Wayne Roberts 3:c012313ebc13 283 #endif /* I2C3_BASE */
Wayne Roberts 3:c012313ebc13 284 #if defined I2C4_BASE
Wayne Roberts 3:c012313ebc13 285 else if (i2c == I2C_4) {
Wayne Roberts 3:c012313ebc13 286 SmbusHandle.Instance = I2C4;
Wayne Roberts 3:c012313ebc13 287 RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2C4;
Wayne Roberts 3:c012313ebc13 288 RCC_PeriphCLKInitStruct.I2c4ClockSelection = RCC_I2C4CLKSOURCE_SYSCLK;
Wayne Roberts 3:c012313ebc13 289 __HAL_RCC_I2C4_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 290 event_i2cIRQ = I2C4_EV_IRQn;
Wayne Roberts 3:c012313ebc13 291 error_i2cIRQ = I2C4_ER_IRQn;
Wayne Roberts 3:c012313ebc13 292
Wayne Roberts 3:c012313ebc13 293 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 294 __HAL_RCC_DMA2_CLK_ENABLE();
Wayne Roberts 3:c012313ebc13 295 dma_ch_tx = DMA1_Channel1;
Wayne Roberts 3:c012313ebc13 296 dma_ch_rx = DMA1_Channel2;
Wayne Roberts 3:c012313ebc13 297 dma_req_tx = DMA_REQUEST_0;
Wayne Roberts 3:c012313ebc13 298 dma_req_rx = DMA_REQUEST_0;
Wayne Roberts 3:c012313ebc13 299 #elif defined(TARGET_STM32L0)
Wayne Roberts 3:c012313ebc13 300 #error absent
Wayne Roberts 3:c012313ebc13 301 #endif
Wayne Roberts 3:c012313ebc13 302 }
Wayne Roberts 3:c012313ebc13 303 #endif /* I2C4_BASE */
Wayne Roberts 3:c012313ebc13 304 else {
Wayne Roberts 3:c012313ebc13 305 mbed_error_printf("unknown i2c %x\r\n", i2c);
Wayne Roberts 3:c012313ebc13 306 return -1;
Wayne Roberts 3:c012313ebc13 307 }
Wayne Roberts 3:c012313ebc13 308
Wayne Roberts 3:c012313ebc13 309 HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct);
Wayne Roberts 3:c012313ebc13 310
Wayne Roberts 3:c012313ebc13 311 // use get_i2c_timing() from i2c_device.h?
Wayne Roberts 0:20421a857bd5 312 SmbusHandle.Init.Timing = I2C_TIMING;
Wayne Roberts 0:20421a857bd5 313 SmbusHandle.Init.AnalogFilter = SMBUS_ANALOGFILTER_ENABLE;
Wayne Roberts 0:20421a857bd5 314 SmbusHandle.Init.OwnAddress1 = slaveAddress;
Wayne Roberts 0:20421a857bd5 315 SmbusHandle.Init.AddressingMode = SMBUS_ADDRESSINGMODE_7BIT;
Wayne Roberts 0:20421a857bd5 316 SmbusHandle.Init.DualAddressMode = SMBUS_DUALADDRESS_DISABLE;
Wayne Roberts 0:20421a857bd5 317 SmbusHandle.Init.OwnAddress2 = 0x00;
Wayne Roberts 0:20421a857bd5 318 SmbusHandle.Init.GeneralCallMode = SMBUS_GENERALCALL_DISABLE;
Wayne Roberts 0:20421a857bd5 319 SmbusHandle.Init.NoStretchMode = SMBUS_NOSTRETCH_DISABLE;
Wayne Roberts 0:20421a857bd5 320 SmbusHandle.Init.PacketErrorCheckMode = SMBUS_PEC_DISABLE;
Wayne Roberts 0:20421a857bd5 321 SmbusHandle.Init.PeripheralMode = SMBUS_PERIPHERAL_MODE_SMBUS_SLAVE;
Wayne Roberts 3:c012313ebc13 322 SmbusHandle.Init.SMBusTimeout = I2C_TIMEOUTR_TIMOUTEN | 0x186;
Wayne Roberts 0:20421a857bd5 323
Wayne Roberts 3:c012313ebc13 324 if (HAL_SMBUS_Init(&SmbusHandle) != HAL_OK)
Wayne Roberts 5:493e5cc9c052 325 {
Wayne Roberts 0:20421a857bd5 326 return -1;
Wayne Roberts 0:20421a857bd5 327 }
Wayne Roberts 0:20421a857bd5 328
Wayne Roberts 0:20421a857bd5 329 tmpisr = SMBUS_IT_ADDRI | SMBUS_IT_STOPI | SMBUS_IT_NACKI | SMBUS_IT_ERRI;
Wayne Roberts 0:20421a857bd5 330 __HAL_SMBUS_ENABLE_IT(&SmbusHandle, tmpisr);
Wayne Roberts 0:20421a857bd5 331
Wayne Roberts 3:c012313ebc13 332 #ifdef TARGET_STM32L4
Wayne Roberts 3:c012313ebc13 333 HAL_NVIC_SetPriority(event_i2cIRQ, 0, 0);
Wayne Roberts 3:c012313ebc13 334 HAL_NVIC_EnableIRQ(event_i2cIRQ);
Wayne Roberts 3:c012313ebc13 335 HAL_NVIC_SetPriority(error_i2cIRQ , 0, 0);
Wayne Roberts 3:c012313ebc13 336 HAL_NVIC_EnableIRQ(error_i2cIRQ);
Wayne Roberts 3:c012313ebc13 337
Wayne Roberts 3:c012313ebc13 338 NVIC_SetVector(event_i2cIRQ, (uint32_t)SMBUSx_EV_IRQHandler);
Wayne Roberts 3:c012313ebc13 339 NVIC_SetVector(error_i2cIRQ, (uint32_t)SMBUSx_ER_IRQHandler);
Wayne Roberts 5:493e5cc9c052 340
Wayne Roberts 3:c012313ebc13 341 #else
Wayne Roberts 3:c012313ebc13 342 HAL_NVIC_SetPriority(event_i2cIRQ, 0, 0);
Wayne Roberts 3:c012313ebc13 343 HAL_NVIC_EnableIRQ(event_i2cIRQ);
Wayne Roberts 3:c012313ebc13 344
Wayne Roberts 3:c012313ebc13 345 NVIC_SetVector(event_i2cIRQ, (uint32_t)SMBUSx_IRQHandler);
Wayne Roberts 3:c012313ebc13 346 #endif
Wayne Roberts 3:c012313ebc13 347
Wayne Roberts 3:c012313ebc13 348 /* Configure the DMA handler for Transmission process */
Wayne Roberts 3:c012313ebc13 349 hdma_tx.Instance = dma_ch_tx;
Wayne Roberts 3:c012313ebc13 350 hdma_tx.Init.Request = dma_req_tx;
Wayne Roberts 3:c012313ebc13 351 hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
Wayne Roberts 3:c012313ebc13 352 hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
Wayne Roberts 3:c012313ebc13 353 hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
Wayne Roberts 3:c012313ebc13 354 hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 355 hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 356 hdma_tx.Init.Mode = DMA_NORMAL;
Wayne Roberts 3:c012313ebc13 357 hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
Wayne Roberts 3:c012313ebc13 358
Wayne Roberts 3:c012313ebc13 359 HAL_DMA_Init(&hdma_tx);
Wayne Roberts 3:c012313ebc13 360
Wayne Roberts 3:c012313ebc13 361 hdma_rx.Instance = dma_ch_rx;
Wayne Roberts 3:c012313ebc13 362 hdma_rx.Init.Request = dma_req_rx;
Wayne Roberts 3:c012313ebc13 363 hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
Wayne Roberts 3:c012313ebc13 364 hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
Wayne Roberts 3:c012313ebc13 365 hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
Wayne Roberts 3:c012313ebc13 366 hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 367 hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
Wayne Roberts 3:c012313ebc13 368 hdma_rx.Init.Mode = DMA_NORMAL;
Wayne Roberts 3:c012313ebc13 369 hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
Wayne Roberts 3:c012313ebc13 370
Wayne Roberts 3:c012313ebc13 371 HAL_DMA_Init(&hdma_rx);
Wayne Roberts 5:493e5cc9c052 372
Wayne Roberts 0:20421a857bd5 373 return 0;
Wayne Roberts 0:20421a857bd5 374 }
Wayne Roberts 0:20421a857bd5 375
Wayne Roberts 0:20421a857bd5 376 static inline uint8_t get_cbuf()
Wayne Roberts 0:20421a857bd5 377 {
Wayne Roberts 0:20421a857bd5 378 uint8_t ret = i2c.cbuf[i2c.cbuf_out];
Wayne Roberts 3:c012313ebc13 379 if (++i2c.cbuf_out == CBUF_SIZE)
Wayne Roberts 0:20421a857bd5 380 i2c.cbuf_out = 0;
Wayne Roberts 0:20421a857bd5 381
Wayne Roberts 0:20421a857bd5 382 return ret;
Wayne Roberts 0:20421a857bd5 383 }
Wayne Roberts 0:20421a857bd5 384
Wayne Roberts 0:20421a857bd5 385 /* service_i2c(): call from main loop */
Wayne Roberts 0:20421a857bd5 386 void service_i2c()
Wayne Roberts 0:20421a857bd5 387 {
Wayne Roberts 0:20421a857bd5 388 if (i2c.cbuf_in != i2c.cbuf_out) {
Wayne Roberts 3:c012313ebc13 389 uint8_t buf[32];
Wayne Roberts 0:20421a857bd5 390 uint8_t n, cmd, len;
Wayne Roberts 0:20421a857bd5 391 cmd = get_cbuf();
Wayne Roberts 0:20421a857bd5 392 len = get_cbuf();
Wayne Roberts 0:20421a857bd5 393 /* host is writing: parse here */
Wayne Roberts 0:20421a857bd5 394 for (n = 0; n < len; n++)
Wayne Roberts 0:20421a857bd5 395 buf[n] = get_cbuf();
Wayne Roberts 0:20421a857bd5 396
Wayne Roberts 0:20421a857bd5 397 /*if (len != cmd_to_length[cmd])
Wayne Roberts 0:20421a857bd5 398 pc.printf("[%02x != %02x] ", len, cmd_to_length[cmd]);*/
Wayne Roberts 0:20421a857bd5 399
Wayne Roberts 0:20421a857bd5 400 service_i2c_write(cmd, len, buf);
Wayne Roberts 0:20421a857bd5 401 }
Wayne Roberts 0:20421a857bd5 402 }
Wayne Roberts 0:20421a857bd5 403