Hi experts,
I habe a following issue. First I have tried to use nrfx_twi driver. There was any data send over I2C...
So I have written own driver using the Datasheet and also received a problem. After sending the data
the RX interrupt is rising. Which causes a logical error. How th driver was realized:
First of all the initial
#define I2C_INSTANCE 1
NRF_TWI_Type *I2C = COMBINE_I2C_NAME(NRF_TWI, I2C_INSTANCE);
void nRF52_I2CInit(uint32_t clkPin, uint32_t dataPin, enum i2CClockRate clockRate, i2cCallbackHandler_t callback)
{
i2cTransaction.callback = callback;
i2cTransaction.busy = true;
// stop I2C
I2C->ENABLE = false;
// configure pins
uint32_t pinConfig;
// set pin configuration
pinConfig = (uint32_t)((uint32_t)INPUT |
(uint32_t)CONNECTED |
(uint32_t)PULLUP |
(uint32_t)S0D1 |
(uint32_t)SENSE_DIS);
// load configuration
if(clkPin < P0_PIN_NUM)
{
NRF_P0->PIN_CNF[clkPin] = pinConfig;
}
else
{
NRF_P1->PIN_CNF[(clkPin & 0x1F)] = pinConfig;
}
if(dataPin < P0_PIN_NUM)
{
NRF_P0->PIN_CNF[dataPin] = pinConfig;
}
else
{
NRF_P1->PIN_CNF[(dataPin & 0x1F)] = pinConfig;
}
// connect pins to TWI
I2C->PSEL.SCL = clkPin;
I2C->PSEL.SDA = dataPin;
// set up clock rate
I2C->FREQUENCY = clockRate;
// disable shorts
I2C->SHORTS = (TWI_SHORTS_BB_STOP_Disabled | TWI_SHORTS_BB_SUSPEND_Disabled);
// set interrupts
I2C->INTENSET = (TWI_INTENSET_ERROR_Msk |
TWI_INTENSET_TXDSENT_Msk |
TWI_INTENSET_RXDREADY_Msk |
TWI_INTENSET_STOPPED_Msk);
// clear all events
I2C->EVENTS_RXDREADY = 0;
I2C->EVENTS_STOPPED = 0;
I2C->EVENTS_SUSPENDED = 0;
I2C->EVENTS_TXDSENT = 0;
I2C->EVENTS_ERROR = 0;
i2cTransaction.busy = false;
NVIC_SetPriority(I2C_IRQNr, 7);
NVIC_ClearPendingIRQ(I2C_IRQNr);
NVIC_EnableIRQ(I2C_IRQNr);
}
After the I2C is configured, a data transfer try was performed:
errorCode_t nRF52_I2C_TX(uint8_t address, uint8_t reg, uint8_t *data, uint8_t length)
{
errorCode_t currentStatus = (errorCode_t)i2cTransaction.busy;
if(currentStatus == 0)
{
// start I2C transfer
I2C->ENABLE = true;
I2C->ADDRESS = address;
// clear all events
I2C->TASKS_STARTTX = 0;
I2C->EVENTS_RXDREADY = 0;
I2C->EVENTS_STOPPED = 0;
I2C->EVENTS_SUSPENDED = 0;
I2C->EVENTS_TXDSENT = 0;
I2C->EVENTS_ERROR = 0;
// clear interrupt
NVIC_ClearPendingIRQ(I2C_IRQNr);
I2C->TXD = reg;
// preapare internal struct
i2cTransaction.dataTx = data;
i2cTransaction.countTx = 0;
i2cTransaction.lengthTX = length;
i2cTransaction.nextOp = TX;
i2cTransaction.errorCode = I2C_SUCCESS;
i2cTransaction.busy = true;
// there is no callback registred -> use blocking
if(i2cTransaction.callback == 0)
{
while (i2cTransaction.busy)
{
__asm("NOP");
}
currentStatus = i2cTransaction.errorCode;
}
}
return currentStatus;
}
The event Manager was realized as following:
void SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler(void)
{
// i2c has an event
// get current error code:
i2cTransaction.errorCode = (errorCode_t)I2C->ERRORSRC;
// check is the transaction ends?
if(I2C->EVENTS_STOPPED)
{
I2C->EVENTS_STOPPED = false;
i2cTransaction.busy = false;
if(i2cTransaction.callback != 0)
{
i2cTransaction.callback(i2cTransaction.errorCode);
}
I2C->ENABLE = false;
}
// is an error occures?
if(I2C->EVENTS_ERROR)
{
// drop all other events
I2C->EVENTS_RXDREADY = 0;
I2C->EVENTS_STOPPED = 0;
I2C->EVENTS_SUSPENDED = 0;
I2C->EVENTS_TXDSENT = 0;
I2C->EVENTS_ERROR = 0;
// clear transaction struct
i2cTransaction.countRx = 0;
i2cTransaction.lengthRX = 0;
i2cTransaction.countRx = 0;
i2cTransaction.lengthRX = 0;
i2cTransaction.busy = false;
if(i2cTransaction.callback != 0)
{
i2cTransaction.callback(i2cTransaction.errorCode);
}
I2C->ENABLE = false;
}
else
{
// i2c has send a byte
if(I2C->EVENTS_TXDSENT)
{
I2C->EVENTS_TXDSENT = false;
// check the operation is transfer only
if(i2cTransaction.nextOp == TX)
{
// check the tranfer shall contunue
if(i2cTransaction.countTx < i2cTransaction.lengthTX)
{
I2C->TASKS_STARTTX = true;
I2C->TXD = i2cTransaction.dataTx[i2cTransaction.countTx++];
}
else
{
I2C->TASKS_STOP = true;
}
}
else
{
// operation is "read register", the read is following
I2C->TASKS_STARTRX = true;
}
}
else if(I2C->EVENTS_RXDREADY) // i2c has received a byte
{
I2C->EVENTS_RXDREADY = false;
if(i2cTransaction.countRx < i2cTransaction.lengthRX)
{
i2cTransaction.dataRx[i2cTransaction.countRx++] = I2C->RXD;
I2C->TASKS_STARTRX = true;
}
else
{
I2C->TASKS_STOP = true;
i2cTransaction.dataRx[i2cTransaction.countRx++] = I2C->RXD;
i2cTransaction.busy = false;
}
}
}
}
After initialization the following data was send:
uint8_t i2CTxBuffer[2]; i2CTxBuffer[0] = 0x35; i2CTxBuffer[1] = 0x70; // send to addess 0x3C, to register 0x35, value 0x70 nRF52_I2C_TX(0x3C, i2CTxBuffer[0], &i2CTxBuffer[1], 1);
As can be seen of the figure below, the TWI do not generate any start/stop conditions. The first and the last byte is send if 0x35. After the firts byte were proessed
the TWI genareted EVENTS_RXDREADY event. Which does not pass, and causes an internal logical error...
Could you explain, what I'm doing wrong?
