Skip to content

Commit

Permalink
NUVOTON: CAN: Fix Rx interrupt doesn't work
Browse files Browse the repository at this point in the history
Major modifications:
1. Handle Rx interrupt based on Message Object interrupt (CAN_IIDR=0x0001~0x0020) instead of CAN_STATUS.RxOK
2. Also handle Tx interrupt following above for consistency

Other related modifications:
1. Fix signature type error in CAN_CLR_INT_PENDING_BIT()
2. Add CAN_CLR_INT_PENDING_ONLY_BIT() which doesn't clear NewDat flag so that user can fetch received message in thread context

NOTE: This fix only targets CAN (NUC472/M453/M487), not CAN-FD (M467).
  • Loading branch information
ccli8 committed Apr 18, 2024
1 parent 63bdb26 commit bfd4ceb
Show file tree
Hide file tree
Showing 9 changed files with 109 additions and 28 deletions.
12 changes: 10 additions & 2 deletions targets/TARGET_NUVOTON/TARGET_M451/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
static uintptr_t can_irq_contexts[CAN_NUM] = {0};
static can_irq_handler can0_irq_handler;

extern uint32_t CAN_IsNewDataReceived(CAN_T *tCAN, uint8_t u8MsgObj);
extern void CAN_CLR_INT_PENDING_ONLY_BIT(CAN_T *tCAN, uint32_t u32MsgNum);

static const struct nu_modinit_s can_modinit_tab[] = {
{CAN_0, CAN0_MODULE, 0, 0, CAN0_RST, CAN0_IRQn, NULL},
Expand Down Expand Up @@ -125,12 +127,10 @@ static void can_irq(CANName name, int id)
/**************************/
if(can->STATUS & CAN_STATUS_RXOK_Msk) {
can->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/
can0_irq_handler(can_irq_contexts[id], IRQ_RX);
}

if(can->STATUS & CAN_STATUS_TXOK_Msk) {
can->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/
can0_irq_handler(can_irq_contexts[id], IRQ_TX);
}

/**************************/
Expand All @@ -143,6 +143,14 @@ static void can_irq(CANName name, int id)
if(can->STATUS & CAN_STATUS_BOFF_Msk) {
can0_irq_handler(can_irq_contexts[id], IRQ_BUS);
}
} else if (u8IIDRstatus >= 1 && u8IIDRstatus <= 32) {
if (CAN_IsNewDataReceived(can, u8IIDRstatus - 1)) {
can0_irq_handler(can_irq_contexts[id], IRQ_RX);
CAN_CLR_INT_PENDING_ONLY_BIT(can, (u8IIDRstatus -1));
} else {
can0_irq_handler(can_irq_contexts[id], IRQ_TX);
CAN_CLR_INT_PENDING_BIT(can, (u8IIDRstatus -1));
}
} else if (u8IIDRstatus!=0) {

can0_irq_handler(can_irq_contexts[id], IRQ_OVERRUN);
Expand Down
15 changes: 14 additions & 1 deletion targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.c
Original file line number Diff line number Diff line change
Expand Up @@ -981,7 +981,7 @@ int32_t CAN_Receive(CAN_T *tCAN, uint32_t u32MsgNum , STR_CANMSG_T* pCanMsg)
*
* @details An interrupt remains pending until the application software has cleared it.
*/
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum)
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint32_t u32MsgNum)
{
uint32_t u32MsgIfNum;

Expand All @@ -994,6 +994,19 @@ void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum)
ReleaseIF(tCAN, u32MsgIfNum);
}

/* Clone of CAN_CLR_INT_PENDING_BIT() with NewDat not cleared */
void CAN_CLR_INT_PENDING_ONLY_BIT(CAN_T *tCAN, uint32_t u32MsgNum)
{
uint32_t u32MsgIfNum;

if((u32MsgIfNum = LockIF_TL(tCAN)) == 2)
u32MsgIfNum = 0;

tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_CLRINTPND_Msk;
tCAN->IF[u32MsgIfNum].CREQ = 1 + u32MsgNum;

ReleaseIF(tCAN, u32MsgIfNum);
}

/*@}*/ /* end of group CAN_EXPORTED_FUNCTIONS */

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ typedef struct
uint32_t CAN_SetBaudRate(CAN_T *tCAN, uint32_t u32BaudRate);
uint32_t CAN_Open(CAN_T *tCAN, uint32_t u32BaudRate, uint32_t u32Mode);
void CAN_Close(CAN_T *tCAN);
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum);
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint32_t u32MsgNum);
void CAN_EnableInt(CAN_T *tCAN, uint32_t u32Mask);
void CAN_DisableInt(CAN_T *tCAN, uint32_t u32Mask);
int32_t CAN_Transmit(CAN_T *tCAN, uint32_t u32MsgNum , STR_CANMSG_T* pCanMsg);
Expand Down
31 changes: 20 additions & 11 deletions targets/TARGET_NUVOTON/TARGET_M480/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ extern void CAN_EnterInitMode(CAN_T *tCAN, uint8_t u8Mask);
extern void CAN_LeaveInitMode(CAN_T *tCAN);
extern void CAN_LeaveTestMode(CAN_T *tCAN);
extern void CAN_EnterTestMode(CAN_T *tCAN, uint8_t u8TestMask);
extern void CAN_CLR_INT_PENDING_ONLY_BIT(CAN_T *tCAN, uint32_t u32MsgNum);

static const struct nu_modinit_s can_modinit_tab[] = {
{CAN_0, CAN0_MODULE, 0, 0, CAN0_RST, CAN0_IRQn, NULL},
Expand Down Expand Up @@ -139,19 +140,10 @@ static void can_irq(CANName name, int id)
/**************************/
if(can->STATUS & CAN_STATUS_RXOK_Msk) {
can->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/
if(id)
can1_irq_handler(can_irq_contexts[id], IRQ_RX);
else
can0_irq_handler(can_irq_contexts[id], IRQ_RX);
}

if(can->STATUS & CAN_STATUS_TXOK_Msk) {
can->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/
if(id)
can1_irq_handler(can_irq_contexts[id], IRQ_TX);
else
can0_irq_handler(can_irq_contexts[id], IRQ_TX);

}

/**************************/
Expand All @@ -170,6 +162,24 @@ static void can_irq(CANName name, int id)
else
can0_irq_handler(can_irq_contexts[id], IRQ_BUS);
}
} else if (u8IIDRstatus >= 1 && u8IIDRstatus <= 32) {
if (CAN_IsNewDataReceived(can, u8IIDRstatus - 1)) {
if (id) {
can1_irq_handler(can_irq_contexts[id], IRQ_RX);
}
else {
can0_irq_handler(can_irq_contexts[id], IRQ_RX);
}
CAN_CLR_INT_PENDING_ONLY_BIT(can, (u8IIDRstatus -1));
} else {
if (id) {
can1_irq_handler(can_irq_contexts[id], IRQ_TX);
}
else {
can0_irq_handler(can_irq_contexts[id], IRQ_TX);
}
CAN_CLR_INT_PENDING_BIT(can, (u8IIDRstatus -1));
}
} else if (u8IIDRstatus!=0) {

if(id)
Expand All @@ -178,7 +188,6 @@ static void can_irq(CANName name, int id)
can0_irq_handler(can_irq_contexts[id], IRQ_OVERRUN);

CAN_CLR_INT_PENDING_BIT(can, ((can->IIDR) -1)); /* Clear Interrupt Pending */

} else if(can->WU_STATUS == 1) {

can->WU_STATUS = 0; /* Write '0' to clear */
Expand Down Expand Up @@ -293,6 +302,7 @@ int can_read(can_t *obj, CAN_Message *msg, int handle)
int can_mode(can_t *obj, CanMode mode)
{
int success = 0;

switch (mode) {
case MODE_RESET:
CAN_LeaveTestMode((CAN_T*)NU_MODBASE(obj->can));
Expand Down Expand Up @@ -326,7 +336,6 @@ int can_mode(can_t *obj, CanMode mode)

}


return success;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ typedef struct
uint32_t CAN_SetBaudRate(CAN_T *tCAN, uint32_t u32BaudRate);
uint32_t CAN_Open(CAN_T *tCAN, uint32_t u32BaudRate, uint32_t u32Mode);
void CAN_Close(CAN_T *tCAN);
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum);
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint32_t u32MsgNum);
void CAN_EnableInt(CAN_T *tCAN, uint32_t u32Mask);
void CAN_DisableInt(CAN_T *tCAN, uint32_t u32Mask);
int32_t CAN_Transmit(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T* pCanMsg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,7 @@ int32_t CAN_Receive(CAN_T *tCAN, uint32_t u32MsgNum, STR_CANMSG_T* pCanMsg)
*
* @details An interrupt remains pending until the application software has cleared it.
*/
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum)
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint32_t u32MsgNum)
{
uint32_t u32MsgIfNum;

Expand All @@ -1282,6 +1282,24 @@ void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum)
ReleaseIF(tCAN, u32MsgIfNum);
}

/* Clone of CAN_CLR_INT_PENDING_BIT() with NewDat not cleared */
void CAN_CLR_INT_PENDING_ONLY_BIT(CAN_T *tCAN, uint32_t u32MsgNum)
{
uint32_t u32MsgIfNum;

if((u32MsgIfNum = LockIF_TL(tCAN)) == 2ul)
{
u32MsgIfNum = 0ul;
}
else
{
}

tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_CLRINTPND_Msk;
tCAN->IF[u32MsgIfNum].CREQ = 1ul + u32MsgNum;

ReleaseIF(tCAN, u32MsgIfNum);
}

/*@}*/ /* end of group CAN_EXPORTED_FUNCTIONS */

Expand Down
29 changes: 20 additions & 9 deletions targets/TARGET_NUVOTON/TARGET_NUC472/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
static can_irq_handler can0_irq_handler;
static can_irq_handler can1_irq_handler;

extern uint32_t CAN_IsNewDataReceived(CAN_T *tCAN, uint8_t u8MsgObj);
extern void CAN_CLR_INT_PENDING_ONLY_BIT(CAN_T *tCAN, uint32_t u32MsgNum);

static const struct nu_modinit_s can_modinit_tab[] = {
{CAN_0, CAN0_MODULE, 0, 0, CAN0_RST, CAN0_IRQn, NULL},
Expand Down Expand Up @@ -133,19 +135,10 @@ static void can_irq(CANName name, int id)
/**************************/
if(can->STATUS & CAN_STATUS_RXOK_Msk) {
can->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/
if(id)
can1_irq_handler(can_irq_contexts[id] , IRQ_RX);
else
can0_irq_handler(can_irq_contexts[id], IRQ_RX);
}

if(can->STATUS & CAN_STATUS_TXOK_Msk) {
can->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/
if(id)
can1_irq_handler(can_irq_contexts[id] , IRQ_TX);
else
can0_irq_handler(can_irq_contexts[id], IRQ_TX);

}

/**************************/
Expand All @@ -164,6 +157,24 @@ static void can_irq(CANName name, int id)
else
can0_irq_handler(can_irq_contexts[id], IRQ_BUS);
}
} else if (u8IIDRstatus >= 1 && u8IIDRstatus <= 32) {
if (CAN_IsNewDataReceived(can, u8IIDRstatus - 1)) {
if (id) {
can1_irq_handler(can_irq_contexts[id], IRQ_RX);
}
else {
can0_irq_handler(can_irq_contexts[id], IRQ_RX);
}
CAN_CLR_INT_PENDING_ONLY_BIT(can, (u8IIDRstatus -1));
} else {
if (id) {
can1_irq_handler(can_irq_contexts[id], IRQ_TX);
}
else {
can0_irq_handler(can_irq_contexts[id], IRQ_TX);
}
CAN_CLR_INT_PENDING_BIT(can, (u8IIDRstatus -1));
}
} else if (u8IIDRstatus!=0) {

if(id)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ int32_t CAN_Receive(CAN_T *tCAN, uint32_t u32MsgNum , STR_CANMSG_T* pCanMsg)
* @return None
*
*/
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum)
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint32_t u32MsgNum)
{
uint32_t u32MsgIfNum = 0;
uint32_t u32IFBusyCount = 0;
Expand All @@ -738,6 +738,28 @@ void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum)

}

/* Clone of CAN_CLR_INT_PENDING_BIT() with NewDat not cleared */
void CAN_CLR_INT_PENDING_ONLY_BIT(CAN_T *tCAN, uint32_t u32MsgNum)
{
uint32_t u32MsgIfNum = 0;
uint32_t u32IFBusyCount = 0;

while(u32IFBusyCount < 0x10000000) {
if((tCAN->IF[0].CREQ & CAN_IF_CREQ_BUSY_Msk) == 0) {
u32MsgIfNum = 0;
break;
} else if((tCAN->IF[1].CREQ & CAN_IF_CREQ_BUSY_Msk) == 0) {
u32MsgIfNum = 1;
break;
}

u32IFBusyCount++;
}

tCAN->IF[u32MsgIfNum].CMASK = CAN_IF_CMASK_CLRINTPND_Msk;
tCAN->IF[u32MsgIfNum].CREQ = 1 + u32MsgNum;

}

/*@}*/ /* end of group NUC472_442_CAN_EXPORTED_FUNCTIONS */

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ uint32_t CAN_SetBaudRate(CAN_T *tCAN, uint32_t u32BaudRate);
uint32_t CAN_Open(CAN_T *tCAN, uint32_t u32BaudRate, uint32_t u32Mode);
int32_t CAN_Transmit(CAN_T *tCAN, uint32_t u32MsgNum , STR_CANMSG_T* pCanMsg);
int32_t CAN_Receive(CAN_T *tCAN, uint32_t u32MsgNum , STR_CANMSG_T* pCanMsg);
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint8_t u32MsgNum);
void CAN_CLR_INT_PENDING_BIT(CAN_T *tCAN, uint32_t u32MsgNum);
void CAN_EnableInt(CAN_T *tCAN, uint32_t u32Mask);
void CAN_DisableInt(CAN_T *tCAN, uint32_t u32Mask);
int32_t CAN_SetMultiRxMsg(CAN_T *tCAN, uint32_t u32MsgNum , uint32_t u32MsgCount, uint32_t u32IDType, uint32_t u32ID);
Expand Down

0 comments on commit bfd4ceb

Please sign in to comment.