From bfd4ceb20bc7d939b44c9f5331589efcfeb5c1a6 Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Mon, 8 Apr 2024 11:16:49 +0800 Subject: [PATCH] NUVOTON: CAN: Fix Rx interrupt doesn't work 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). --- targets/TARGET_NUVOTON/TARGET_M451/can_api.c | 12 +++++-- .../TARGET_M451/device/StdDriver/m451_can.c | 15 ++++++++- .../TARGET_M451/device/StdDriver/m451_can.h | 2 +- targets/TARGET_NUVOTON/TARGET_M480/can_api.c | 31 ++++++++++++------- .../device/StdDriver/inc/m480_can.h | 2 +- .../device/StdDriver/src/m480_can.c | 20 +++++++++++- .../TARGET_NUVOTON/TARGET_NUC472/can_api.c | 29 +++++++++++------ .../device/StdDriver/nuc472_can.c | 24 +++++++++++++- .../device/StdDriver/nuc472_can.h | 2 +- 9 files changed, 109 insertions(+), 28 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M451/can_api.c b/targets/TARGET_NUVOTON/TARGET_M451/can_api.c index 678de11109..42d2975b2d 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/can_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/can_api.c @@ -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}, @@ -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); } /**************************/ @@ -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); diff --git a/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.c b/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.c index 7cc61939cf..8afa0731b2 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.c @@ -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; @@ -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 */ diff --git a/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.h b/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.h index d2427af227..91af319703 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.h +++ b/targets/TARGET_NUVOTON/TARGET_M451/device/StdDriver/m451_can.h @@ -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); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/can_api.c b/targets/TARGET_NUVOTON/TARGET_M480/can_api.c index 00a840b98f..d16e3ef15b 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/can_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/can_api.c @@ -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}, @@ -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); - } /**************************/ @@ -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) @@ -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 */ @@ -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)); @@ -326,7 +336,6 @@ int can_mode(can_t *obj, CanMode mode) } - return success; } diff --git a/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/inc/m480_can.h b/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/inc/m480_can.h index 0aca5fd847..552f0a78d1 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/inc/m480_can.h +++ b/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/inc/m480_can.h @@ -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); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/src/m480_can.c b/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/src/m480_can.c index f299343617..3930e570df 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/src/m480_can.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/device/StdDriver/src/m480_can.c @@ -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; @@ -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 */ diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/can_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/can_api.c index 7ea08e771e..c940848964 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/can_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/can_api.c @@ -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}, @@ -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); - } /**************************/ @@ -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) diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.c b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.c index 673d884697..0464aa509e 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.c @@ -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; @@ -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 */ diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.h b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.h index 65e63fa747..3601586a16 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.h +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/device/StdDriver/nuc472_can.h @@ -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);