Skip to content

Commit

Permalink
Merge pull request #15509 from OpenNuvoton/nuvoton_fix_can_interrupt
Browse files Browse the repository at this point in the history
NUVOTON: CAN: Fix Rx interrupt and filter mask
  • Loading branch information
0xc0170 authored Apr 23, 2024
2 parents 7ae592d + c1c9550 commit 8502c74
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 41 deletions.
40 changes: 32 additions & 8 deletions targets/TARGET_NUVOTON/TARGET_M451/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,25 @@
#include "nu_miscutil.h"
#include "nu_bitutil.h"
#include "mbed_critical.h"
#include "mbed_error.h"

#define NU_CAN_DEBUG 0
#define CAN_NUM 1

/* Reserve Message Object number 31 for Tx */
#define NU_CAN_MSG_OBJ_NUM_TX 31

/* Max number of message ID filter handle */
#define NU_CAN_MAXNUM_HNDL NU_CAN_MSG_OBJ_NUM_TX

/* Convert to string literal */
#define NU_STR_(X) #X
#define NU_STR(X) NU_STR_(X)

static uintptr_t can_irq_contexts[CAN_NUM] = {0};
static can_irq_handler can0_irq_handler;

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 +137,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 +153,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 ((u8IIDRstatus - 1) != NU_CAN_MSG_OBJ_NUM_TX) {
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 Expand Up @@ -213,6 +231,9 @@ void can_irq_set(can_t *obj, CanIrqType irq, uint32_t enable)

int can_write(can_t *obj, CAN_Message msg, int cc)
{
/* Unused */
(void) cc;

STR_CANMSG_T CMsg;

CMsg.IdType = (uint32_t)msg.format;
Expand All @@ -221,7 +242,7 @@ int can_write(can_t *obj, CAN_Message msg, int cc)
CMsg.DLC = msg.len;
memcpy((void *)&CMsg.Data[0],(const void *)&msg.data[0], (unsigned int)8);

return CAN_Transmit((CAN_T *)NU_MODBASE(obj->can), cc, &CMsg);
return CAN_Transmit((CAN_T *)NU_MODBASE(obj->can), NU_CAN_MSG_OBJ_NUM_TX, &CMsg);
}

int can_read(can_t *obj, CAN_Message *msg, int handle)
Expand Down Expand Up @@ -285,16 +306,19 @@ int can_mode(can_t *obj, CanMode mode)

int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle)
{
uint32_t numask = mask;
if( numask == 0x0000 )
{
return CAN_SetRxMsg((CAN_T *)NU_MODBASE(obj->can), handle, (uint32_t)format, id);
/* Check validity of filter handle */
if (handle < 0 || handle >= NU_CAN_MAXNUM_HNDL) {
/* NOTE: 0 is ambiguous, error or filter handle 0. */
error("Support max " NU_STR(NU_CAN_MAXNUM_HNDL) " CAN filters");
return 0;
}

uint32_t numask = mask;
if( format == CANStandard )
{
numask = (mask << 18);
}
numask = (numask | CAN_IF_MASK2_MDIR_Msk | CAN_IF_MASK2_MXTD_Msk);
numask = (numask | ((CAN_IF_MASK2_MDIR_Msk | CAN_IF_MASK2_MXTD_Msk) << 16));
return CAN_SetRxMsgAndMsk((CAN_T *)NU_MODBASE(obj->can), handle, (uint32_t)format, id, numask);
}

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
60 changes: 43 additions & 17 deletions targets/TARGET_NUVOTON/TARGET_M480/can_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,21 @@
#include "nu_miscutil.h"
#include "nu_bitutil.h"
#include "mbed_critical.h"
#include "mbed_error.h"

#define NU_CAN_DEBUG 0
#define CAN_NUM 2

/* Reserve Message Object number 31 for Tx */
#define NU_CAN_MSG_OBJ_NUM_TX 31

/* Max number of message ID filter handle */
#define NU_CAN_MAXNUM_HNDL NU_CAN_MSG_OBJ_NUM_TX

/* Convert to string literal */
#define NU_STR_(X) #X
#define NU_STR(X) NU_STR_(X)

static uintptr_t can_irq_contexts[CAN_NUM] = {0};
static can_irq_handler can0_irq_handler;
static can_irq_handler can1_irq_handler;
Expand All @@ -43,6 +54,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 +151,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 +173,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 ((u8IIDRstatus - 1) != NU_CAN_MSG_OBJ_NUM_TX) {
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 +199,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 @@ -263,6 +283,9 @@ void can_irq_set(can_t *obj, CanIrqType irq, uint32_t enable)

int can_write(can_t *obj, CAN_Message msg, int cc)
{
/* Unused */
(void) cc;

STR_CANMSG_T CMsg;

CMsg.IdType = (uint32_t)msg.format;
Expand All @@ -271,7 +294,7 @@ int can_write(can_t *obj, CAN_Message msg, int cc)
CMsg.DLC = msg.len;
memcpy((void *)&CMsg.Data[0],(const void *)&msg.data[0], (unsigned int)8);

return CAN_Transmit((CAN_T *)(NU_MODBASE(obj->can)), cc, &CMsg);
return CAN_Transmit((CAN_T *)(NU_MODBASE(obj->can)), NU_CAN_MSG_OBJ_NUM_TX, &CMsg);
}

int can_read(can_t *obj, CAN_Message *msg, int handle)
Expand All @@ -293,6 +316,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,22 +350,24 @@ int can_mode(can_t *obj, CanMode mode)

}


return success;
}

int can_filter(can_t *obj, uint32_t id, uint32_t mask, CANFormat format, int32_t handle)
{
uint32_t numask = mask;
if( numask == 0x0000 )
{
return CAN_SetRxMsg((CAN_T *)NU_MODBASE(obj->can), handle, (uint32_t)format, id);
/* Check validity of filter handle */
if (handle < 0 || handle >= NU_CAN_MAXNUM_HNDL) {
/* NOTE: 0 is ambiguous, error or filter handle 0. */
error("Support max " NU_STR(NU_CAN_MAXNUM_HNDL) " CAN filters");
return 0;
}

uint32_t numask = mask;
if( format == CANStandard )
{
numask = (mask << 18);
}
numask = (numask | CAN_IF_MASK2_MDIR_Msk | CAN_IF_MASK2_MXTD_Msk);
numask = (numask | ((CAN_IF_MASK2_MDIR_Msk | CAN_IF_MASK2_MXTD_Msk) << 16));
return CAN_SetRxMsgAndMsk((CAN_T *)NU_MODBASE(obj->can), handle, (uint32_t)format, id, numask);
}

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
Loading

0 comments on commit 8502c74

Please sign in to comment.