I am trying to port the KL25Z Accelerometer I2C example to FreeRTOS so that instead of using the SDK's I2C driver it uses the FreeRTOS's I2C driver.
After configuring I2C pins and release I2C bus I try to Init the IC2 RTOS driver.
I2C_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Bps = I2C_BAUDRATE;
sourceClock = ACCEL_I2C_CLK_FREQ;
//I2C_MasterInit(BOARD_ACCEL_I2C_BSEADDR, &masterConfig, sourceClock);
NVIC_SetPriority(ACCEL_I2C_MASTER_IRQN, configMAX_PRIORITIES - 1);status = I2C_RTOS_Init(&master_rtos_handle, ACCEL_I2C_MASTER, &masterConfig, sourceClock);
status reported to be 0x00
Then I configure the first transfer message
i2c_master_transfer_t masterXfer;
memset(&masterXfer, 0, sizeof(masterXfer));masterXfer.slaveAddress = 0x1DU;
masterXfer.direction = kI2C_Write;
masterXfer.subaddress = 0;
masterXfer.subaddressSize = 0;
masterXfer.data = &who_am_i_reg;
masterXfer.dataSize = 1;
masterXfer.flags = kI2C_TransferNoStopFlag;
This message is only to check that the Accelerometer is there. The slave Adress direction is already set to 0x1DU because I want to jump the part of the example which tries a set of addresses to check devices.
Then I start the transfer:
g_m_handle = &master_rtos_handle.drv_handle;
status = I2C_RTOS_Transfer(&master_rtos_handle, &masterXfer);
The task goes inside the I2C_RTOS_Transfer takes the semaphore and starts:
status = I2C_MasterTransferNonBlocking(handle->base, &handle->drv_handle, transfer);
if (status != kStatus_Success)
{
xSemaphoreGive(handle->mutex);
return status;
}
status again reported to be 0x00 so the transfer is a sucess.
But then the task tries to Take the semaphore again but the semaphore is never given.
/* Wait for transfer to finish */
xSemaphoreTake(handle->semaphore, portMAX_DELAY);
If I am not mistaken after the I2C_MasterTransferNonBlocking is completed the task should call I2C_RTOS_Callback which in turn should Give the Semaphore.
static void I2C_RTOS_Callback(I2C_Type *base, i2c_master_handle_t *drv_handle, status_t status, void *userData)
{i2c_rtos_handle_t *handle = (i2c_rtos_handle_t *)userData;
BaseType_t reschedule;
handle->async_status = status;
xSemaphoreGiveFromISR(handle->semaphore, &reschedule);
portYIELD_FROM_ISR(reschedule);}
But the I2C_RTOS_Callback is never called so the semaphore is never given and so the code hangs in
xSemaphoreTake(handle->semaphore, portMAX_DELAY);
I tried the code with a set of priorities higher and lower than 5, but none seem to work.The debugger trace shows that the program follows this path:
xSemaphoreTake -> xQueueGenericReceive --> vTaskPlaceOnEventList ---> vListInsert --> pxNewListItem->pxNext = pxIterator->pxNext; --> ldr r0,=HardFault_Handler
What on earth I am missing here?
Thank you.
已解决! 转到解答。
Update 1: The problem seems to be that if I try to use (transfer - receive functions ) I2C RTOS driver at the main loop before creating the tasks and starting the scheduler the system seems to enter that hard fault in the xQueue.
I think that my design is incorrect due to whatever i am missing to allow me use I2C RTOS driver (transfer - receive functions) at the main function before starting the task scheduler. I think in the rtos examples provided by the SDK they all configure RTOS driver in the main loop and then use the transfer receive functions inside the task after starting the scheduler an the task themselves.
I did that design only because I need to send and receive to configure the external devices before entering the reading tasks. That's it just wanting to configure things before starting all scheduler stuff.
How to allow the RTOS use IRQ - Callbacks at main before starting the scheduler?