[Squash] Move I2C to IRQ based for big txn

Squash DMA attempt out

.
This commit is contained in:
Ben V. Brown
2025-02-21 18:42:17 +11:00
parent abefe96072
commit 5e8d44e07f
9 changed files with 382 additions and 484 deletions

View File

@@ -7,17 +7,80 @@
#include "BSP.h"
#include "IRQ.h"
#include "Setup.h"
#include "bl_mcu_sdk/drivers/bl702_driver/std_drv/inc/bl702_dma.h"
extern "C" {
#include "bflb_platform.h"
#include "bl702_dma.h"
#include "bl702_glb.h"
#include "bl702_i2c.h"
}
#include <I2C_Wrapper.hpp>
// Semaphore for locking users of I2C
SemaphoreHandle_t FRToSI2C::I2CSemaphore = nullptr;
StaticSemaphore_t FRToSI2C::xSemaphoreBuffer;
#define I2C_TIME_OUT (uint16_t)(12000)
void FRToSI2C::CpltCallback() {} // Not used
#define I2C_TIME_OUT (uint16_t)(12000)
#define I2C_TX_FIFO_ADDR (0x4000A300 + 0x88)
// Used by the irq handler
volatile uint8_t *irq_data_ptr;
volatile uint8_t irq_data_size_left;
/****** IRQ Handlers ******/
void i2c_irq_tx_fifo_low() {
// Filling tx fifo
// Fifo is 32 bit, LSB sent first
// FiFo can store up to 2, 32-bit words
// So we fill it until it has no free room (or we run out of data)
while (irq_data_size_left > 0 && I2C_GetTXFIFOAvailable() > 0) {
// Can put in at least 1 byte
// Build a 32-bit word from bytes
uint32_t value = 0;
for (int i = 0; i < 4 && irq_data_size_left > 0; i++) {
value >>= 8;
value |= (*irq_data_ptr) << 24; // Shift to the left, adding new data to the higher byte
irq_data_ptr++; // Shift to next byte
irq_data_size_left--;
}
// Push the new value to the fifo
*((volatile uint32_t *)I2C_TX_FIFO_ADDR) = value;
}
if (irq_data_size_left == 0) {
// Disable IRQ, were done
I2C_IntMask(I2C0_ID, I2C_TX_FIFO_READY_INT, MASK);
}
}
void i2c_irq_done() {
// Mask IRQ's back off
I2C_IntMask(I2C0_ID, I2C_TRANS_END_INT, MASK);
I2C_IntMask(I2C0_ID, I2C_NACK_RECV_INT, MASK);
FRToSI2C::CpltCallback(); // Causes the lock to be released
}
void i2c_irq_nack() {
// Mask IRQ's back off
I2C_IntMask(I2C0_ID, I2C_TRANS_END_INT, MASK);
I2C_IntMask(I2C0_ID, I2C_NACK_RECV_INT, MASK);
FRToSI2C::CpltCallback(); // Causes the lock to be released
}
/****** END IRQ Handlers ******/
void FRToSI2C::CpltCallback() {
// This is only triggered from IRQ context
I2C_Disable(I2C0_ID); // Disable I2C to tidy up
// Unlock the semaphore && allow task switch if desired by RTOS
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(I2CSemaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
bool FRToSI2C::I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data) { return Mem_Write(address, reg, &data, 1); }
@@ -56,6 +119,7 @@ bool FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, uint8_t *p_bu
if (!lock()) {
return false;
}
I2C_Transfer_Cfg i2cCfg = {0, DISABLE, 0, 0, 0, 0};
BL_Err_Type err = ERROR;
i2cCfg.slaveAddr = DevAddress >> 1;
@@ -65,16 +129,36 @@ bool FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, uint8_t *p_bu
i2cCfg.data = p_buffer;
i2cCfg.subAddrSize = 1; // one byte address
vTaskSuspendAll();
/* --------------- */
err = I2C_MasterSendBlocking(I2C0_ID, &i2cCfg);
xTaskResumeAll();
bool res = err == SUCCESS;
if (!res) {
I2C_Unstick();
if (number_of_byte <= 32) {
vTaskSuspendAll();
/* --------------- */
err = I2C_MasterSendBlocking(I2C0_ID, &i2cCfg);
xTaskResumeAll();
bool res = err == SUCCESS;
if (!res) {
I2C_Unstick();
}
unlock();
return res;
} else {
// Store handles for IRQ
irq_data_ptr = p_buffer;
irq_data_size_left = number_of_byte;
// Setup and run
I2C_Init(I2C0_ID, I2C_WRITE, &i2cCfg); // Setup hardware for the I2C init header with the device address
I2C_IntMask(I2C0_ID, I2C_TRANS_END_INT, UNMASK);
I2C_IntMask(I2C0_ID, I2C_NACK_RECV_INT, UNMASK);
I2C_IntMask(I2C0_ID, I2C_TX_FIFO_READY_INT, UNMASK);
I2C_Int_Callback_Install(I2C0_ID, I2C_TRANS_END_INT, i2c_irq_done);
I2C_Int_Callback_Install(I2C0_ID, I2C_NACK_RECV_INT, i2c_irq_nack);
I2C_Int_Callback_Install(I2C0_ID, I2C_TX_FIFO_READY_INT, i2c_irq_tx_fifo_low);
i2c_irq_tx_fifo_low(); // Pre-fill fifo
// Start
I2C_Enable(I2C0_ID);
// Dont unlock as tx is still ongoing, will be cleared in irq of i2c finishing
return true;
}
unlock();
return res;
}
bool FRToSI2C::Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size) { return Mem_Write(DevAddress, pData[0], pData + 1, Size - 1); }