Move mem_read to new state format

This commit is contained in:
Ben V. Brown
2021-02-23 22:11:50 +11:00
parent e5a29ae9fb
commit c53c28914e

View File

@@ -15,7 +15,9 @@ void FRToSI2C::CpltCallback() {
// TODO // TODO
} }
bool FRToSI2C::I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data) { return Mem_Write(address, reg, &data, 1); } bool FRToSI2C::I2C_RegisterWrite(uint8_t address, uint8_t reg, uint8_t data) {
return Mem_Write(address, reg, &data, 1);
}
uint8_t FRToSI2C::I2C_RegisterRead(uint8_t add, uint8_t reg) { uint8_t FRToSI2C::I2C_RegisterRead(uint8_t add, uint8_t reg) {
uint8_t temp = 0; uint8_t temp = 0;
@@ -23,33 +25,70 @@ uint8_t FRToSI2C::I2C_RegisterRead(uint8_t add, uint8_t reg) {
return temp; return temp;
} }
enum i2c_step {
//Write+read steps
Write_start, //Sending start on bus
Write_device_address, //start sent, send device address
Write_device_memory_address, //device address sent, write the memory location
Write_device_data_start, // Write all of the remaining data using DMA
Write_device_data_wait, // Write all of the remaining data using DMA
Read_start, //second read
Read_device_address, // Send device address again for the read
Read_device_data_start, //read device data via DMA
Read_device_data_finish, //read device data via DMA
Send_stop, // send the stop at the end of the transaction
Wait_stop, // Wait for stop to send and we are done
Done, //Finished
Error_occured, //Error occured on the bus
};
struct i2c_state {
i2c_step currentStep;
dma_parameter_struct dma_init_struct;
};
volatile i2c_state currentState;
bool FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t read_address, uint8_t *p_buffer, uint16_t number_of_byte) { bool FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t read_address, uint8_t *p_buffer, uint16_t number_of_byte) {
if (!lock()) if (!lock())
return false; return false;
i2c_interrupt_disable(I2C0, I2C_INT_ERR); i2c_interrupt_disable(I2C0, I2C_INT_ERR);
i2c_interrupt_disable(I2C0, I2C_INT_BUF); i2c_interrupt_disable(I2C0, I2C_INT_BUF);
i2c_interrupt_disable(I2C0, I2C_INT_EV); i2c_interrupt_disable(I2C0, I2C_INT_EV);
dma_parameter_struct dma_init_struct; //Setup DMA
dma_deinit(DMA0, DMA_CH6);
currentState.dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
currentState.dma_init_struct.memory_addr = (uint32_t) p_buffer;
currentState.dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
currentState.dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
currentState.dma_init_struct.number = number_of_byte;
currentState.dma_init_struct.periph_addr = (uint32_t) &I2C_DATA(I2C0);
currentState.dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
currentState.dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
currentState.dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA0, DMA_CH6, (dma_parameter_struct*) &currentState.dma_init_struct);
uint8_t state = I2C_START; i2c_dma_last_transfer_config(I2C0, I2C_DMALST_ON);
uint8_t in_rx_cycle = 0;
uint16_t timeout = 0; currentState.currentStep = Write_start;
uint8_t tries = 0; TickType_t timeout = xTaskGetTickCount() + TICKS_SECOND;
uint8_t i2c_timeout_flag = 0; while ((currentState.currentStep != Done) && (currentState.currentStep != Error_occured)) {
while (!(i2c_timeout_flag)) { if (xTaskGetTickCount() > timeout) {
switch (state) {
case I2C_START:
tries++;
if (tries > 64) {
i2c_stop_on_bus(I2C0); i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */ I2C_Unstick();
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
unlock(); unlock();
return false; return false;
} }
if (0 == in_rx_cycle) { switch (currentState.currentStep) {
case Error_occured:
i2c_stop_on_bus(I2C0);
I2C_Unstick();
unlock();
return false;
break;
case Write_start:
/* disable I2C0 */ /* disable I2C0 */
i2c_disable(I2C0); i2c_disable(I2C0);
/* enable I2C0 */ /* enable I2C0 */
@@ -58,112 +97,65 @@ bool FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t read_address, uint8_t *p_b
/* enable acknowledge */ /* enable acknowledge */
i2c_ack_config(I2C0, I2C_ACK_ENABLE); i2c_ack_config(I2C0, I2C_ACK_ENABLE);
/* i2c master sends start signal only when the bus is idle */ /* i2c master sends start signal only when the bus is idle */
while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { if (!i2c_flag_get(I2C0, I2C_FLAG_I2CBSY)) {
timeout++;
}
if (timeout < I2C_TIME_OUT) {
/* send the start signal */ /* send the start signal */
i2c_start_on_bus(I2C0); i2c_start_on_bus(I2C0);
timeout = 0; currentState.currentStep = Write_device_address;
state = I2C_SEND_ADDRESS;
} else {
I2C_Unstick();
timeout = 0;
state = I2C_START;
} }
} else { break;
case Read_start:
/* wait until BTC bit is set */
if (i2c_flag_get(I2C0, I2C_FLAG_BTC)) {
i2c_start_on_bus(I2C0); i2c_start_on_bus(I2C0);
timeout = 0; currentState.currentStep = Read_device_address;
state = I2C_SEND_ADDRESS;
} }
break; break;
case I2C_SEND_ADDRESS: case Write_device_address:
/* i2c master sends START signal successfully */ /* i2c master sends START signal successfully */
while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) { if (i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) {
timeout++;
}
if (timeout < I2C_TIME_OUT) {
if (RESET == in_rx_cycle) {
i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER); i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER);
state = I2C_CLEAR_ADDRESS_FLAG; currentState.currentStep = Write_device_memory_address;
} else { }
break;
case Read_device_address:
if (i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) {
i2c_master_addressing(I2C0, DevAddress, I2C_RECEIVER); i2c_master_addressing(I2C0, DevAddress, I2C_RECEIVER);
state = I2C_CLEAR_ADDRESS_FLAG; currentState.currentStep = Read_device_data_start;
}
timeout = 0;
} else {
timeout = 0;
state = I2C_START;
in_rx_cycle = 0;
} }
break; break;
case I2C_CLEAR_ADDRESS_FLAG: case Write_device_memory_address:
/* address flag set means i2c slave sends ACK */ //Send the device memory location
while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { if (i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { //addr sent
timeout++;
if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
i2c_flag_clear(I2C0, I2C_FLAG_AERR); //Arb error - we lost the bus / nacked
i2c_stop_on_bus(I2C0); currentState.currentStep = Error_occured;
/* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) {
timeout++;
} }
// Address NACK'd if (i2c_flag_get(I2C0, I2C_FLAG_TBE)) {
unlock();
return false;
}
}
if (timeout < I2C_TIME_OUT) {
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
timeout = 0;
state = I2C_TRANSMIT_DATA;
} else {
i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
// Address NACK'd
unlock();
return false;
}
break;
case I2C_TRANSMIT_DATA:
if (0 == in_rx_cycle) {
/* wait until the transmit data buffer is empty */
while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if (timeout < I2C_TIME_OUT) {
// Write out the 8 byte address // Write out the 8 byte address
i2c_data_transmit(I2C0, read_address); i2c_data_transmit(I2C0, read_address);
timeout = 0; currentState.currentStep = Read_start;
} else {
timeout = 0;
state = I2C_START;
in_rx_cycle = 0;
} }
/* wait until BTC bit is set */
while ((!i2c_flag_get(I2C0, I2C_FLAG_BTC)) && (timeout < I2C_TIME_OUT)) {
timeout++;
} }
if (timeout < I2C_TIME_OUT) { break;
timeout = 0; case Read_device_data_start:
state = I2C_START; if (i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { //addr sent
in_rx_cycle = 1; if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
} else { //Arb error - we lost the bus / nacked
timeout = 0; currentState.currentStep = Error_occured;
state = I2C_START;
in_rx_cycle = 0;
} }
} else { i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); //TODO may not be able to do this
/* one byte master reception procedure (polling) */ /* one byte master reception procedure (polling) */
if (number_of_byte < 2) { if (number_of_byte == 0) {
currentState.currentStep = Send_stop;
} else if (number_of_byte == 1) {
/* disable acknowledge */ /* disable acknowledge */
i2c_ack_config(I2C0, I2C_ACK_DISABLE); i2c_ack_config(I2C0, I2C_ACK_DISABLE);
/* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register /* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register
* (I2C_STAT0 has already been read) */ * (I2C_STAT0 has already been read) */
i2c_flag_get(I2C0, I2C_FLAG_ADDSEND); i2c_flag_get(I2C0, I2C_FLAG_ADDSEND); //sat0
i2c_flag_get(I2C0, I2C_FLAG_I2CBSY); //sat1
/* send a stop condition to I2C bus*/ /* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C0); i2c_stop_on_bus(I2C0);
/* wait for the byte to be received */ /* wait for the byte to be received */
@@ -171,57 +163,38 @@ bool FRToSI2C::Mem_Read(uint16_t DevAddress, uint16_t read_address, uint8_t *p_b
; ;
/* read the byte received from the EEPROM */ /* read the byte received from the EEPROM */
*p_buffer = i2c_data_receive(I2C0); *p_buffer = i2c_data_receive(I2C0);
/* decrement the read bytes counter */ currentState.currentStep = Wait_stop;
number_of_byte--;
timeout = 0;
} else { /* more than one byte master reception procedure (DMA) */ } else { /* more than one byte master reception procedure (DMA) */
dma_deinit(DMA0, DMA_CH6);
dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
dma_init_struct.memory_addr = (uint32_t)p_buffer;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = number_of_byte;
dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C0);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA0, DMA_CH6, &dma_init_struct);
i2c_dma_last_transfer_config(I2C0, I2C_DMALST_ON);
/* enable I2C0 DMA */ /* enable I2C0 DMA */
i2c_dma_enable(I2C0, I2C_DMA_ON); i2c_dma_enable(I2C0, I2C_DMA_ON);
/* enable DMA0 channel5 */ /* enable DMA0 channel5 */
dma_channel_enable(DMA0, DMA_CH6); dma_channel_enable(DMA0, DMA_CH6);
/* wait until BTC bit is set */ currentState.currentStep = Read_device_data_finish;
while (!dma_flag_get(DMA0, DMA_CH6, DMA_FLAG_FTF)) {}
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C0);
} }
timeout = 0;
state = I2C_STOP;
} }
break; break;
case I2C_STOP: case Read_device_data_finish: //Wait for complete then goto stop
/* i2c master sends STOP signal successfully */ /* wait until BTC bit is set */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { if (dma_flag_get(DMA0, DMA_CH6, DMA_FLAG_FTF)) {
timeout++; currentState.currentStep = Send_stop;
} }
if (timeout < I2C_TIME_OUT) {
timeout = 0; break;
state = I2C_END; case Send_stop:
i2c_timeout_flag = I2C_OK; /* send a stop condition to I2C bus*/
} else { i2c_stop_on_bus(I2C0);
timeout = 0; currentState.currentStep = Wait_stop;
state = I2C_START; break;
in_rx_cycle = 0; case Wait_stop:
/* i2c master sends STOP signal successfully */
if ((I2C_CTL0(I2C0) & 0x0200) != 0x0200) {
currentState.currentStep = Done;
} }
break; break;
default: default:
state = I2C_START; //If we get here something is amiss
in_rx_cycle = 0; unlock();
i2c_timeout_flag = I2C_OK; return false;
timeout = 0;
break;
} }
} }
unlock(); unlock();
@@ -339,9 +312,11 @@ bool FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, uint8_t *p_bu
/* enable DMA0 channel5 */ /* enable DMA0 channel5 */
dma_channel_enable(DMA0, DMA_CH5); dma_channel_enable(DMA0, DMA_CH5);
/* wait until BTC bit is set */ /* wait until BTC bit is set */
while (!dma_flag_get(DMA0, DMA_CH5, DMA_FLAG_FTF)) {} while (!dma_flag_get(DMA0, DMA_CH5, DMA_FLAG_FTF)) {
}
/* wait until BTC bit is set */ /* wait until BTC bit is set */
while (!i2c_flag_get(I2C0, I2C_FLAG_BTC)) {} while (!i2c_flag_get(I2C0, I2C_FLAG_BTC)) {
}
state = I2C_STOP; state = I2C_STOP;
break; break;
case I2C_STOP: case I2C_STOP:
@@ -372,14 +347,18 @@ bool FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, uint8_t *p_bu
return timedout == false; return timedout == false;
} }
bool FRToSI2C::Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size) { return Mem_Write(DevAddress, pData[0], pData + 1, Size - 1); } bool FRToSI2C::Transmit(uint16_t DevAddress, uint8_t *pData, uint16_t Size) {
return Mem_Write(DevAddress, pData[0], pData + 1, Size - 1);
}
bool FRToSI2C::probe(uint16_t DevAddress) { bool FRToSI2C::probe(uint16_t DevAddress) {
uint8_t temp[1]; uint8_t temp[1];
return Mem_Read(DevAddress, 0x00, temp, sizeof(temp)); return Mem_Read(DevAddress, 0x00, temp, sizeof(temp));
} }
void FRToSI2C::I2C_Unstick() { unstick_I2C(); } void FRToSI2C::I2C_Unstick() {
unstick_I2C();
}
bool FRToSI2C::lock() { bool FRToSI2C::lock() {
if (I2CSemaphore == nullptr) { if (I2CSemaphore == nullptr) {
@@ -388,7 +367,9 @@ bool FRToSI2C::lock() {
return xSemaphoreTake(I2CSemaphore, TICKS_SECOND) == pdTRUE; return xSemaphoreTake(I2CSemaphore, TICKS_SECOND) == pdTRUE;
} }
void FRToSI2C::unlock() { xSemaphoreGive(I2CSemaphore); } void FRToSI2C::unlock() {
xSemaphoreGive(I2CSemaphore);
}
bool FRToSI2C::writeRegistersBulk(const uint8_t address, const I2C_REG *registers, const uint8_t registersLength) { bool FRToSI2C::writeRegistersBulk(const uint8_t address, const I2C_REG *registers, const uint8_t registersLength) {
for (int index = 0; index < registersLength; index++) { for (int index = 0; index < registersLength; index++) {
@@ -507,3 +488,11 @@ bool FRToSI2C::wakePart(uint16_t DevAddress) {
unlock(); unlock();
return timedout == false; return timedout == false;
} }
void I2C_EV_IRQ() {
}
void I2C_ER_IRQ() {
//Error callbacks
}