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

@@ -12,498 +12,487 @@ SemaphoreHandle_t FRToSI2C::I2CSemaphore = nullptr;
StaticSemaphore_t FRToSI2C::xSemaphoreBuffer; StaticSemaphore_t FRToSI2C::xSemaphoreBuffer;
#define I2C_TIME_OUT (uint16_t)(12000) #define I2C_TIME_OUT (uint16_t)(12000)
void FRToSI2C::CpltCallback() { 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;
Mem_Read(add, reg, &temp, 1); Mem_Read(add, reg, &temp, 1);
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;
uint8_t tries = 0;
uint8_t i2c_timeout_flag = 0;
while (!(i2c_timeout_flag)) {
switch (state) {
case I2C_START:
tries++;
if (tries > 64) {
i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
unlock();
return false;
}
if (0 == in_rx_cycle) {
/* disable I2C0 */
i2c_disable(I2C0);
/* enable I2C0 */
i2c_enable(I2C0);
/* enable acknowledge */ currentState.currentStep = Write_start;
i2c_ack_config(I2C0, I2C_ACK_ENABLE); TickType_t timeout = xTaskGetTickCount() + TICKS_SECOND;
/* i2c master sends start signal only when the bus is idle */ while ((currentState.currentStep != Done) && (currentState.currentStep != Error_occured)) {
while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT)) { if (xTaskGetTickCount() > timeout) {
timeout++; i2c_stop_on_bus(I2C0);
} I2C_Unstick();
if (timeout < I2C_TIME_OUT) { unlock();
/* send the start signal */ return false;
i2c_start_on_bus(I2C0); }
timeout = 0; switch (currentState.currentStep) {
state = I2C_SEND_ADDRESS; case Error_occured:
} else {
I2C_Unstick();
timeout = 0;
state = I2C_START;
}
} else {
i2c_start_on_bus(I2C0);
timeout = 0;
state = I2C_SEND_ADDRESS;
}
break;
case I2C_SEND_ADDRESS:
/* i2c master sends START signal successfully */
while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if (timeout < I2C_TIME_OUT) {
if (RESET == in_rx_cycle) {
i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER);
state = I2C_CLEAR_ADDRESS_FLAG;
} else {
i2c_master_addressing(I2C0, DevAddress, I2C_RECEIVER);
state = I2C_CLEAR_ADDRESS_FLAG;
}
timeout = 0;
} else {
timeout = 0;
state = I2C_START;
in_rx_cycle = 0;
}
break;
case I2C_CLEAR_ADDRESS_FLAG:
/* address flag set means i2c slave sends ACK */
while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) {
timeout++;
if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
i2c_flag_clear(I2C0, I2C_FLAG_AERR);
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;
}
}
if (timeout < I2C_TIME_OUT) {
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
i2c_data_transmit(I2C0, read_address);
timeout = 0;
} 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) {
timeout = 0;
state = I2C_START;
in_rx_cycle = 1;
} else {
timeout = 0;
state = I2C_START;
in_rx_cycle = 0;
}
} else {
/* one byte master reception procedure (polling) */
if (number_of_byte < 2) {
/* disable acknowledge */
i2c_ack_config(I2C0, I2C_ACK_DISABLE);
/* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register
* (I2C_STAT0 has already been read) */
i2c_flag_get(I2C0, I2C_FLAG_ADDSEND);
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C0);
/* wait for the byte to be received */
while (!i2c_flag_get(I2C0, I2C_FLAG_RBNE))
;
/* read the byte received from the EEPROM */
*p_buffer = i2c_data_receive(I2C0);
/* decrement the read bytes counter */
number_of_byte--;
timeout = 0;
} 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); i2c_stop_on_bus(I2C0);
/* enable I2C0 DMA */ I2C_Unstick();
i2c_dma_enable(I2C0, I2C_DMA_ON); unlock();
/* enable DMA0 channel5 */ return false;
dma_channel_enable(DMA0, DMA_CH6); break;
/* wait until BTC bit is set */ case Write_start:
while (!dma_flag_get(DMA0, DMA_CH6, DMA_FLAG_FTF)) {}
/* send a stop condition to I2C bus*/ /* disable I2C0 */
i2c_stop_on_bus(I2C0); i2c_disable(I2C0);
} /* enable I2C0 */
timeout = 0; i2c_enable(I2C0);
state = I2C_STOP;
} /* enable acknowledge */
break; i2c_ack_config(I2C0, I2C_ACK_ENABLE);
case I2C_STOP: /* i2c master sends start signal only when the bus is idle */
/* i2c master sends STOP signal successfully */ if (!i2c_flag_get(I2C0, I2C_FLAG_I2CBSY)) {
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { /* send the start signal */
timeout++; i2c_start_on_bus(I2C0);
} currentState.currentStep = Write_device_address;
if (timeout < I2C_TIME_OUT) { }
timeout = 0; break;
state = I2C_END; case Read_start:
i2c_timeout_flag = I2C_OK; /* wait until BTC bit is set */
} else { if (i2c_flag_get(I2C0, I2C_FLAG_BTC)) {
timeout = 0; i2c_start_on_bus(I2C0);
state = I2C_START; currentState.currentStep = Read_device_address;
in_rx_cycle = 0; }
} break;
break; case Write_device_address:
default: /* i2c master sends START signal successfully */
state = I2C_START; if (i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) {
in_rx_cycle = 0; i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER);
i2c_timeout_flag = I2C_OK; currentState.currentStep = Write_device_memory_address;
timeout = 0; }
break; break;
} case Read_device_address:
} if (i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) {
unlock(); i2c_master_addressing(I2C0, DevAddress, I2C_RECEIVER);
return true; currentState.currentStep = Read_device_data_start;
}
break;
case Write_device_memory_address:
//Send the device memory location
if (i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { //addr sent
if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
//Arb error - we lost the bus / nacked
currentState.currentStep = Error_occured;
}
if (i2c_flag_get(I2C0, I2C_FLAG_TBE)) {
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
// Write out the 8 byte address
i2c_data_transmit(I2C0, read_address);
currentState.currentStep = Read_start;
}
}
break;
case Read_device_data_start:
if (i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) { //addr sent
if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
//Arb error - we lost the bus / nacked
currentState.currentStep = Error_occured;
}
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); //TODO may not be able to do this
/* one byte master reception procedure (polling) */
if (number_of_byte == 0) {
currentState.currentStep = Send_stop;
} else if (number_of_byte == 1) {
/* disable acknowledge */
i2c_ack_config(I2C0, I2C_ACK_DISABLE);
/* clear ADDSEND register by reading I2C_STAT0 then I2C_STAT1 register
* (I2C_STAT0 has already been read) */
i2c_flag_get(I2C0, I2C_FLAG_ADDSEND); //sat0
i2c_flag_get(I2C0, I2C_FLAG_I2CBSY); //sat1
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C0);
/* wait for the byte to be received */
while (!i2c_flag_get(I2C0, I2C_FLAG_RBNE))
;
/* read the byte received from the EEPROM */
*p_buffer = i2c_data_receive(I2C0);
currentState.currentStep = Wait_stop;
} else { /* more than one byte master reception procedure (DMA) */
/* enable I2C0 DMA */
i2c_dma_enable(I2C0, I2C_DMA_ON);
/* enable DMA0 channel5 */
dma_channel_enable(DMA0, DMA_CH6);
currentState.currentStep = Read_device_data_finish;
}
}
break;
case Read_device_data_finish: //Wait for complete then goto stop
/* wait until BTC bit is set */
if (dma_flag_get(DMA0, DMA_CH6, DMA_FLAG_FTF)) {
currentState.currentStep = Send_stop;
}
break;
case Send_stop:
/* send a stop condition to I2C bus*/
i2c_stop_on_bus(I2C0);
currentState.currentStep = Wait_stop;
break;
case Wait_stop:
/* i2c master sends STOP signal successfully */
if ((I2C_CTL0(I2C0) & 0x0200) != 0x0200) {
currentState.currentStep = Done;
}
break;
default:
//If we get here something is amiss
unlock();
return false;
}
}
unlock();
return true;
} }
bool FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, uint8_t *p_buffer, uint16_t number_of_byte) { bool FRToSI2C::Mem_Write(uint16_t DevAddress, uint16_t MemAddress, 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_EV); i2c_interrupt_disable(I2C0, I2C_INT_EV);
i2c_interrupt_disable(I2C0, I2C_INT_BUF); i2c_interrupt_disable(I2C0, I2C_INT_BUF);
dma_parameter_struct dma_init_struct; dma_parameter_struct dma_init_struct;
uint8_t state = I2C_START; uint8_t state = I2C_START;
uint16_t timeout = 0; uint16_t timeout = 0;
bool done = false; bool done = false;
bool timedout = false; bool timedout = false;
while (!(done || timedout)) { while (!(done || timedout)) {
switch (state) { switch (state) {
case I2C_START: case I2C_START:
/* 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)) { while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
i2c_start_on_bus(I2C0); i2c_start_on_bus(I2C0);
timeout = 0; timeout = 0;
state = I2C_SEND_ADDRESS; state = I2C_SEND_ADDRESS;
} else { } else {
I2C_Unstick(); I2C_Unstick();
timeout = 0; timeout = 0;
state = I2C_START; state = I2C_START;
} }
break; break;
case I2C_SEND_ADDRESS: case I2C_SEND_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)) { while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER); i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER);
timeout = 0; timeout = 0;
state = I2C_CLEAR_ADDRESS_FLAG; state = I2C_CLEAR_ADDRESS_FLAG;
} else { } else {
timedout = true; timedout = true;
done = true; done = true;
timeout = 0; timeout = 0;
state = I2C_START; state = I2C_START;
} }
break; break;
case I2C_CLEAR_ADDRESS_FLAG: case I2C_CLEAR_ADDRESS_FLAG:
/* address flag set means i2c slave sends ACK */ /* address flag set means i2c slave sends ACK */
while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
i2c_flag_clear(I2C0, I2C_FLAG_AERR); i2c_flag_clear(I2C0, I2C_FLAG_AERR);
i2c_stop_on_bus(I2C0); i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */ /* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
// Address NACK'd // Address NACK'd
unlock(); unlock();
return false; return false;
} }
} }
timeout = 0; timeout = 0;
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
state = I2C_TRANSMIT_DATA; state = I2C_TRANSMIT_DATA;
} else { } else {
// Dont retry as this means a NAK // Dont retry as this means a NAK
i2c_stop_on_bus(I2C0); i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */ /* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
unlock(); unlock();
return false; return false;
} }
break; break;
case I2C_TRANSMIT_DATA: case I2C_TRANSMIT_DATA:
/* wait until the transmit data buffer is empty */ /* wait until the transmit data buffer is empty */
while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT)) { while ((!i2c_flag_get(I2C0, I2C_FLAG_TBE)) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
/* send the EEPROM's internal address to write to : only one byte /* send the EEPROM's internal address to write to : only one byte
* address */ * address */
i2c_data_transmit(I2C0, MemAddress); i2c_data_transmit(I2C0, MemAddress);
timeout = 0; timeout = 0;
} else { } else {
timedout = true; timedout = true;
timeout = 0; timeout = 0;
state = I2C_START; state = I2C_START;
} }
/* 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))
; ;
dma_deinit(DMA0, DMA_CH5); dma_deinit(DMA0, DMA_CH5);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL; dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = (uint32_t)p_buffer; dma_init_struct.memory_addr = (uint32_t) p_buffer;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT; dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = number_of_byte; dma_init_struct.number = number_of_byte;
dma_init_struct.periph_addr = (uint32_t)&I2C_DATA(I2C0); dma_init_struct.periph_addr = (uint32_t) &I2C_DATA(I2C0);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT; dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH; dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA0, DMA_CH5, &dma_init_struct); dma_init(DMA0, DMA_CH5, &dma_init_struct);
/* 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_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 */ }
while (!i2c_flag_get(I2C0, I2C_FLAG_BTC)) {} /* wait until BTC bit is set */
state = I2C_STOP; while (!i2c_flag_get(I2C0, I2C_FLAG_BTC)) {
break; }
case I2C_STOP: state = I2C_STOP;
/* send a stop condition to I2C bus */ break;
i2c_stop_on_bus(I2C0); case I2C_STOP:
/* i2c master sends STOP signal successfully */ /* send a stop condition to I2C bus */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { i2c_stop_on_bus(I2C0);
timeout++; /* i2c master sends STOP signal successfully */
} while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT )) {
if (timeout < I2C_TIME_OUT) { timeout++;
timeout = 0; }
state = I2C_END; if (timeout < I2C_TIME_OUT) {
done = true; timeout = 0;
} else { state = I2C_END;
timedout = true; done = true;
done = true; } else {
timeout = 0; timedout = true;
state = I2C_START; done = true;
} timeout = 0;
break; state = I2C_START;
default: }
state = I2C_START; break;
timeout = 0; default:
break; state = I2C_START;
} timeout = 0;
} break;
unlock(); }
return timedout == false; }
unlock();
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) {
return false; return false;
} }
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++) {
if (!I2C_RegisterWrite(address, registers[index].reg, registers[index].val)) { if (!I2C_RegisterWrite(address, registers[index].reg, registers[index].val)) {
return false; return false;
} }
if (registers[index].pause_ms) { if (registers[index].pause_ms) {
delay_ms(registers[index].pause_ms); delay_ms(registers[index].pause_ms);
} }
} }
return true; return true;
} }
bool FRToSI2C::wakePart(uint16_t DevAddress) { bool FRToSI2C::wakePart(uint16_t DevAddress) {
// wakepart is a special case where only the device address is sent // wakepart is a special case where only the device address is sent
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_EV); i2c_interrupt_disable(I2C0, I2C_INT_EV);
i2c_interrupt_disable(I2C0, I2C_INT_BUF); i2c_interrupt_disable(I2C0, I2C_INT_BUF);
uint8_t state = I2C_START; uint8_t state = I2C_START;
uint16_t timeout = 0; uint16_t timeout = 0;
bool done = false; bool done = false;
bool timedout = false; bool timedout = false;
while (!(done || timedout)) { while (!(done || timedout)) {
switch (state) { switch (state) {
case I2C_START: case I2C_START:
/* 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)) { while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
i2c_start_on_bus(I2C0); i2c_start_on_bus(I2C0);
timeout = 0; timeout = 0;
state = I2C_SEND_ADDRESS; state = I2C_SEND_ADDRESS;
} else { } else {
I2C_Unstick(); I2C_Unstick();
timeout = 0; timeout = 0;
state = I2C_START; state = I2C_START;
} }
break; break;
case I2C_SEND_ADDRESS: case I2C_SEND_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)) { while ((!i2c_flag_get(I2C0, I2C_FLAG_SBSEND)) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER); i2c_master_addressing(I2C0, DevAddress, I2C_TRANSMITTER);
timeout = 0; timeout = 0;
state = I2C_CLEAR_ADDRESS_FLAG; state = I2C_CLEAR_ADDRESS_FLAG;
} else { } else {
timedout = true; timedout = true;
done = true; done = true;
timeout = 0; timeout = 0;
state = I2C_START; state = I2C_START;
} }
break; break;
case I2C_CLEAR_ADDRESS_FLAG: case I2C_CLEAR_ADDRESS_FLAG:
/* address flag set means i2c slave sends ACK */ /* address flag set means i2c slave sends ACK */
while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT)) { while ((!i2c_flag_get(I2C0, I2C_FLAG_ADDSEND)) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) { if (i2c_flag_get(I2C0, I2C_FLAG_AERR)) {
i2c_flag_clear(I2C0, I2C_FLAG_AERR); i2c_flag_clear(I2C0, I2C_FLAG_AERR);
i2c_stop_on_bus(I2C0); i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */ /* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
// Address NACK'd // Address NACK'd
unlock(); unlock();
return false; return false;
} }
} }
if (timeout < I2C_TIME_OUT) { if (timeout < I2C_TIME_OUT) {
i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND); i2c_flag_clear(I2C0, I2C_FLAG_ADDSEND);
timeout = 0; timeout = 0;
state = I2C_STOP; state = I2C_STOP;
} else { } else {
// Dont retry as this means a NAK // Dont retry as this means a NAK
i2c_stop_on_bus(I2C0); i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */ /* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) { while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT )) {
timeout++; timeout++;
} }
unlock(); unlock();
return false; return false;
} }
break; break;
case I2C_STOP:
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT )) {
timeout++;
}
if (timeout < I2C_TIME_OUT) {
timeout = 0;
state = I2C_END;
done = true;
} else {
timedout = true;
done = true;
timeout = 0;
state = I2C_START;
}
break;
default:
state = I2C_START;
timeout = 0;
break;
}
}
unlock();
return timedout == false;
}
void I2C_EV_IRQ() {
}
void I2C_ER_IRQ() {
//Error callbacks
case I2C_STOP:
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C0);
/* i2c master sends STOP signal successfully */
while ((I2C_CTL0(I2C0) & 0x0200) && (timeout < I2C_TIME_OUT)) {
timeout++;
}
if (timeout < I2C_TIME_OUT) {
timeout = 0;
state = I2C_END;
done = true;
} else {
timedout = true;
done = true;
timeout = 0;
state = I2C_START;
}
break;
default:
state = I2C_START;
timeout = 0;
break;
}
}
unlock();
return timedout == false;
} }