PN7462 I2CM configuration Hi team, I am using PN7462 controller and the following I2CM initialization and EEPROM read implementation, which works correctly in the PN7462AU_ex_phExHif demo project: phStatus_t I2C_Init(void)
{
phStatus_t status;
uint8_t bBaudRate;
bBaudRate = (uint8_t)
((PH_EXHIF_HW_CRYSTAL_CLK / 100000UL) -
PH_EXHIF_HW_CRYSTAL_CLK_MHZ);
status = phhalI2CM_Init(
PH_EXHIF_HW_I2CM_TX_FIFO_THRES,
PH_EXHIF_HW_I2CM_RX_FIFO_THRES,
PH_EXHIF_HW_I2CM_TIMEOUT,
PH_EXHIF_HW_I2CM_RETRY_CNT);
if(status != PH_ERR_SUCCESS)
{
return status;
}
status = phhalI2CM_Config(
0x40,
0x09,
E_I2CM_7BIT_ADDR_MODE);
return status;
}
#define EEPROM_ADDR (0x50U)
#define EEPROM_MFG_ADDR (0xFAU)
#define EEPROM_DEV_ADDR (0xFBU)
#define EEPROM_UID_ADDR (0xFCU)
phStatus_t EEPROM_ReadUID(uint8_t uid[4])
{
return EEPROM_Read(
EEPROM_UID_ADDR,
uid,
4);
}
static phStatus_t EEPROM_Read(uint8_t memAddr,
uint8_t *pData,
uint16_t length)
{
phStatus_t status;
uint32_t txBuf[4];
uint32_t rxBuf[64] = {0};
txBuf[0] = memAddr;
status = phhalI2CM_Transmit(
EEPROM_ADDR,
1,
txBuf);
if(status != PH_ERR_SUCCESS)
{
return status;
}
status = phhalI2CM_Receive(
EEPROM_ADDR,
length,
rxBuf);
if(status != PH_ERR_SUCCESS)
{
return status;
}
memcpy(pData, (uint8_t *)rxBuf, length);
return PH_ERR_SUCCESS;
} int main(void) { /* Boot initialization */ phFlashBoot_Main(); /* LED init */ phLED_Init(); /* UART init */ UART_Init(); I2C_Init(); EEPROM_WriteRead_Test(); while(1) { /* Everything handled in callbacks */ } } This exact code works in the PN7462AU_ex_phExHif demo. However, when integrated into my application and also phExMain example, it causes a HardFault. is there any additional configuration required in phExMain and on my application for I2CM operation? Re: PN7462 I2CM configuration Hi @EduardoZamora I investigated the issue further and found a difference between the HIF demo and our application. The HIF demo is running with the NULL OS implementation, whereas our application is running with FreeRTOS. After starting the I2C transaction, the driver waits for an event to be posted from the I2C ISR when the transfer completes. In our application, the I2C ISR eventually calls: phStatus_t phOsal_EventPost(phOsal_Event_t * eventHandle,
phOsal_EventOpt_t options,
phOsal_EventBits_t FlagsToPost,
phOsal_EventBits_t *pCurrFlags)
{
BaseType_t HigherPriorityTaskWoken;
phOsal_EventBits_t CurrentFlags;
if((eventHandle == NULL) || ((*eventHandle) == NULL))
{
return (PH_OSAL_ERROR | PH_COMP_OSAL);
}
HigherPriorityTaskWoken = pdFALSE;
if (xPortIsInsideInterrupt() == pdTRUE)
{
CurrentFlags = xEventGroupSetBitsFromISR(
*eventHandle,
FlagsToPost,
&HigherPriorityTaskWoken);
if(CurrentFlags == pdPASS)
{
portYIELD_FROM_ISR(HigherPriorityTaskWoken);
}
}
else
{
CurrentFlags = xEventGroupSetBits(
*eventHandle,
FlagsToPost);
}
if (pCurrFlags != NULL)
{
*pCurrFlags = CurrentFlags;
}
return PH_OSAL_SUCCESS;
} While debugging, the execution flow is: I2C ISR
-> phOsal_EventPost()
-> xEventGroupSetBitsFromISR()
-> xTimerPendFunctionCallFromISR()
-> xQueueSendFromISR() Inside FreeRTOS: BaseType_t xTimerPendFunctionCallFromISR(
PendedFunction_t xFunctionToPend,
void * pvParameter1,
uint32_t ulParameter2,
BaseType_t * pxHigherPriorityTaskWoken )
{
DaemonTaskMessage_t xMessage;
BaseType_t xReturn = pdPASS;
xMessage.xMessageID = tmrCOMMAND_EXECUTE_CALLBACK_FROM_ISR;
xMessage.u.xCallbackParameters.pxCallbackFunction = xFunctionToPend;
xMessage.u.xCallbackParameters.pvParameter1 = pvParameter1;
xMessage.u.xCallbackParameters.ulParameter2 = ulParameter2;
xReturn = xQueueSendFromISR(
xTimerQueue,
&xMessage,
pxHigherPriorityTaskWoken );
return xReturn;
} At this point, xTimerQueue is NULL. xQueueSendFromISR() checks the queue handle using: configASSERT(pxQueue); and our assert is defined as: #define configASSERT(x) \
if((x) == 0) \
{ \
taskDISABLE_INTERRUPTS(); \
for(;;); \
} Since xTimerQueue is NULL, the code enters the infinite loop. When running normally, it eventually results in a HardFault. For comparison, the NULL OS implementation of phOsal_EventPost() is: phStatus_t phOsal_EventPost(
phOsal_Event_t * eventHandle,
phOsal_EventOpt_t options,
phOsal_EventBits_t FlagsToPost,
phOsal_EventBits_t *pCurrFlags)
{
if((eventHandle == NULL) || ((*eventHandle) == NULL))
{
return PH_OSAL_ADD_COMPCODE(PH_OSAL_ERROR, PH_COMP_OSAL);
}
phOsal_EnterCriticalSection();
(*((uint32_t *)(*eventHandle))) |= FlagsToPost;
if (pCurrFlags != NULL)
{
*pCurrFlags = (*((uint32_t *)(*eventHandle)));
}
phOsal_ExitCriticalSection();
phOsal_WakeUp();
return PH_OSAL_SUCCESS;
} This implementation does not use Event Groups, Timer Service Tasks, or Timer Queues, so it works correctly in the HIF demo. Could you please advise whether additional FreeRTOS timer service initialization is required before using the I2C/HIF drivers, or if there is a recommended FreeRTOS configuration for this use case? Thanks. Re: PN7462 I2CM configuration Hello @uday_gowda
Could you please confirm what is the instruction that triggers the HardFault?
Please consider that some demo projects, such as phExMain, may use a large amount of memory, and adding functionality may exceed the available space. I will recommend you scaling down the project to the minimal functionality required by your application.
Regards, Eduardo.
View full article