SAMC / Bosch TTCAN controller - Page 1
Forum section: electronics / general

author: Simon
author_rank: Unknown
timestamp: February 12, 2024, 05:06:30 pm
content: I have this very weird situation where I have CAN0 set up to send and receive 1 extended message and CAN1 to receive 1 standard message and send several. As soon as I enable an Rx filter the transmissions just stop, I think when the same amount of messages have been sent as there is space in the rx buffer. The transmission of a message triggers a response of 4 messages of which one is being filtered.The code for the two channels is the same baring CAN0 replaced with CAN1On pausing the device I find it in the void interrupt:void Dummy_Handler(void){while (1) {}}

author: ataradov
author_rank: Super Contributor
timestamp: February 12, 2024, 05:17:40 pm
content: This is just a generic interrupt/fault handler. Look in the IPSR register and check the index of the interrupt that caused that handler.It is likely to be 3 for the Hard Fault or some value greater than 15 for the interrupts index.If it is 3, then you will have to debug what causes that fault.

author: Simon
author_rank: Unknown
timestamp: February 12, 2024, 05:56:10 pm
content: It's very odd code is pretty much this. I guess I should have created one big structure for each and then arrayed them but more haste = less speed and duplicate code.RAM buffers:Code:void *can_0_rx_variable_index[CAN_0_STD_MESSAGE_FILTER_NUM + CAN_0_EXD_MESSAGE_FILTER_NUM] ;void *can_1_rx_variable_index[CAN_1_STD_MESSAGE_FILTER_NUM + CAN_1_EXD_MESSAGE_FILTER_NUM] ;/********************************* RAM variables - buffers, FIFO's and filter elements ************************************/CanMramXifde can_0_rx_exd_filter ; // extended id filter elementscan_std_filter_element_t can_0_rx_std_filter ; // standard id filter elementscan_fifo_t can_0_rx_buffer ; // receive buffercan_tx_data_t can_0_tx_buffer ; // transmit bufferCanMramXifde can_1_rx_exd_filter ; // extended id filter elementscan_std_filter_element_t can_1_rx_std_filter ; // standard id filter elementscan_fifo_t can_1_rx_buffer ; // receive buffercan_tx_data_t can_1_tx_buffer ; // transmit buffersetup:Code:void can_init(Can * instance ){uint8_t n = ret_can_port_n(instance) ;connect_peripheral_to_clock((per_clock_channel_CAN0 + n), F_48MHz) ; // connect clock to CPU clock, bridge connection made in clock setupinstance->CCCR.bit.INIT = 1 ; // put the can peripheral into initialization modeinstance->CCCR.bit.CCE = 1 ; // enable writing of registers while in initialization modeinstance->CCCR.bit.TXP = 0 ; // Transmit pause enabled. The CAN pauses for two CAN bit times before starting the next transmission after itself has successfully transmitted a frame.instance->CCCR.bit.DAR = 0 ; // Automatic retransmission of messages not transmitted successfully disabled.instance->NBTP.bit.NBRP = (can_clock / (can_baudrate * 16U) ) - 1 ; //prescaler to obtain the arbitration field quantization clock max 511, a 1 is added by the hardware preventing division by 0.....instance->TSCC.bit.TCP = 0xF ; // time stamp counter prescaler, actual value is +1 as dividing by "0" is - "silly".//instance->TSCC.bit.TSS = 0x1 ; // enable this internal time stamp counter use system time counter instead// Global filter configurationinstance->GFC.reg = 0x2 << 4 // Accept Non-matching Frames Standard: 0 = into FIFO 0, 1 = into FIFO 1, 2 or 3 reject| 0x2 << 2 // Accept Non-matching Frames Extended: 0 = into FIFO 0, 1 = into FIFO 1, 2 or 3 reject| 0x1 << 1 // Reject Remote Frames Standard : 0 = filter as normal, 1 = reject| 0x1 << 0 ; // Reject Remote Frames Extended : 0 = filter as normal, 1 = rejectinstance->MRCFG.bit.QOS = 0x3 ;if (n == 0U){// transmit FIFO0 settingsinstance->TXBC.reg = (0xFFFF & ( (uint32_t) can_0_tx_buffer)) | CAN_TXBC_NDTB(CAN_0_TX_BUFFER_NUM) | CAN_TXBC_TFQS(CAN_0_TX_FIFO_NUM) ; // TFQM left out as left at "0"// receive FIFO0 settingsinstance->RXF0C.reg = CAN_RXF0C_F0SA( (uint32_t) (can_0_rx_buffer)) | CAN_RXF0C_F0S(CAN_0_RX_FIFO_0_NUM) ;// rx standard filter settingsif (CAN_0_STD_MESSAGE_FILTER_NUM){instance->SIDFC.reg = CAN_SIDFC_FLSSA( (uint32_t) can_0_rx_std_filter ) | CAN_SIDFC_LSS(CAN_0_STD_MESSAGE_FILTER_NUM) ;}// rx extended filter settingsif (CAN_0_EXD_MESSAGE_FILTER_NUM){instance->XIDFC.reg = CAN_0_EXD_MESSAGE_FILTER_NUM << 16 | ( ( (uint32_t) can_0_rx_exd_filter ) & 0xFFFFUL ) ;}interrupt_enable(NVIC_INT_CAN0_CH) ;}if (n == 1U){// transmit FIFO0 settingsinstance->TXBC.reg = (0xFFFF & ( (uint32_t) can_1_tx_buffer)) | CAN_TXBC_NDTB(CAN_1_TX_BUFFER_NUM) | CAN_TXBC_TFQS(CAN_1_TX_FIFO_NUM) ; // TFQM left out as left at "0"// receive FIFO0 settingsinstance->RXF0C.reg = CAN_RXF0C_F0SA( (uint32_t) (can_1_rx_buffer)) | CAN_RXF0C_F0S(CAN_1_RX_FIFO_0_NUM) ;// rx standard filter settingsif (CAN_1_STD_MESSAGE_FILTER_NUM){instance->SIDFC.reg = CAN_1_STD_MESSAGE_FILTER_NUM << 16 | ( ( (uint32_t) can_1_rx_std_filter ) & 0xFFFFUL ) ;}if (CAN_1_EXD_MESSAGE_FILTER_NUM){instance->XIDFC.reg = CAN_1_EXD_MESSAGE_FILTER_NUM << 16 | ( ( (uint32_t) can_1_rx_exd_filter ) & 0xFFFFUL ) ;}interrupt_enable(NVIC_INT_CAN1_CH) ;}// interrupts enableinstance->IE.bit.RF0NE = 0x1 ; // message received interruptinstance->ILE.reg = 0x1 ; // enable interrupt line 0instance->CCCR.bit.INIT = 0 ; // conclude can configuration}RX handlersCode:void CAN0_Handler_rx_by_id(){if (CAN0->IR.bit.RF0N){static can_rx_data_t sorting_buffer ;static uint8_t n ;n = CAN0->RXF0S.bit.F0GI ; // make n the get indexCAN0->IR.reg = 0x1 << 0 ; // reset RF0N Rx FIFO 0 New Messagesorting_buffer.time_stamp = ret_rtc_us() ;// copy data bytes only from RX fifo into holding variable that has the same layout as can_rx_data_t data types.memcpy(&sorting_buffer , &can_0_rx_buffer.CAN_BUFFER_DATA , 8) ;uint8_t exd_id_bit = can_0_rx_buffer.XTD ; // check for extended frameCAN0->RXF0A.bit.F0AI = n ;// acknowledge data read so that get index increases// memcpy from the sorting buffer variable to the destination variable.if (exd_id_bit){sorting_buffer.id = can_0_rx_buffer.ID ; // use exd_id_bit as shifting enabler to shift the std id downmemcpy(can_0_rx_variable_index[ can_0_rx_buffer.FIDX + CAN_0_STD_MESSAGE_FILTER_NUM - 1 ] , &sorting_buffer , 32 ) ;}else{sorting_buffer.id = can_0_rx_buffer.ID >> 18 ;memcpy(can_0_rx_variable_index[ can_0_rx_buffer.FIDX ] , &sorting_buffer , 32 ) ;}}}void CAN1_Handler_rx_by_id(){if (CAN1->IR.bit.RF0N){static can_rx_data_t sorting_buffer ;static uint8_t can1_get_index ;can1_get_index = CAN1->RXF0S.bit.F0GI ; // make n the get indexCAN1->IR.reg = 0x1 << 0 ; // reset RF0N Rx FIFO 0 New Messagesorting_buffer.time_stamp = ret_rtc_us() ;// copy data bytes only from RX fifo into holding variable that has the same layout as can_rx_data_t data types.memcpy(&sorting_buffer , &can_1_rx_buffer.CAN_BUFFER_DATA , can_1_rx_buffer.DLC) ;uint8_t exd_id_bit = can_1_rx_buffer.XTD ; // check for extended frameCAN1->RXF0A.bit.F0AI = can1_get_index ;// acknowledge data read so that get index increases// memcpy from the sorting buffer variable to the destination variable.if (exd_id_bit){sorting_buffer.id = can_1_rx_buffer.ID ;memcpy(can_1_rx_variable_index[ can_1_rx_buffer.FIDX + CAN_1_STD_MESSAGE_FILTER_NUM - 1 ] , &sorting_buffer , 32 ) ;}else{sorting_buffer.id = can_1_rx_buffer.ID >> 18 ; // use exd_id_bit as shifting enabler to shift the std id downmemcpy(can_1_rx_variable_index[ can_1_rx_buffer.FIDX ] , &sorting_buffer , 32 ) ;}}}RX filters setupvoid can_std_filter_setup(Can * instance , uint16_t id , uint8_t filter_element_n , void * variable ){uint8_t n = ret_can_port_n(instance) ;if (n == 0){can_0_rx_variable_index = variable ; // add the address of the allocated variable to the to the array that points to variables by ID/ filter element number// see MTTCAN 2.4.5can_0_rx_std_filter.bit.SFEC = 0x1 ; // store in FIFO 0can_0_rx_std_filter.bit.SFID1 = id ; // message idcan_0_rx_std_filter.bit.SFID2 = id ; // message idcan_0_rx_std_filter.bit.SFT = 0x1 ; // dual id filter}if (n == 1){can_1_rx_variable_index = variable ; // add the address of the allocated variable to the to the array that points to variables by ID/ filter element number// see MTTCAN 2.4.5can_1_rx_std_filter.bit.SFEC = 0x1 ; // store in FIFO 0can_1_rx_std_filter.bit.SFID1 = id ; // message idcan_1_rx_std_filter.bit.SFID2 = id ; // message idcan_1_rx_std_filter.bit.SFT = 0x1 ; // dual id filter}}void can_exd_filter_setup(Can * instance , uint32_t id , uint8_t filter_element_n , void * variable ){uint8_t n = ret_can_port_n(instance) ;if (n == 0){can_0_rx_variable_index[filter_element_n + CAN_0_STD_MESSAGE_FILTER_NUM - 1U] = variable ; // add the address of the allocated variable to the to the array that points to variables by ID/ filter element number// see MTTCANcan_0_rx_exd_filter.XIDFE_0.bit.EFEC = 0x1 ;can_0_rx_exd_filter.XIDFE_0.bit.EFID1 = id ;can_0_rx_exd_filter.XIDFE_1.bit.EFT = 0x1 ;can_0_rx_exd_filter.XIDFE_1.bit.EFID2 = id ;}if (n == 1){can_1_rx_variable_index[filter_element_n + CAN_1_STD_MESSAGE_FILTER_NUM - 1U] = variable ; // add the address of the allocated variable to the to the array that points to variables by ID/ filter element number// see MTTCANcan_1_rx_exd_filter.XIDFE_0.bit.EFEC = 0x1 ;can_1_rx_exd_filter.XIDFE_0.bit.EFID1 = id ;can_1_rx_exd_filter.XIDFE_1.bit.EFT = 0x1 ;can_1_rx_exd_filter.XIDFE_1.bit.EFID2 = id ;}}

author: Simon
author_rank: Unknown
timestamp: February 12, 2024, 05:57:39 pm
content: The received data is always identical in the buffer so it is going where it should and is not being written to random places.

author: ataradov
author_rank: Super Contributor
timestamp: February 12, 2024, 06:08:22 pm
content: Again, check the IPSR value first.

author: Simon
author_rank: Unknown
timestamp: February 12, 2024, 06:26:08 pm
content: right, will do in the morning when I am back in.

author: Simon
author_rank: Unknown
timestamp: February 13, 2024, 09:05:27 am
content: Right, there is no IPSR register that i can find. there is a register called ICSR (https://developer.arm.com/documentation/107706/0100/Exceptions-and-interrupts-overview/SCB-registers-for-system-exception-management/Interrupt-Control-and-State-Register--SCB--ICSR-?lang=en) which seems to do the same. and yes the vectactive value is 3.What I also note is that this problem is not simply due to reception on CAN1 being enabled. the system works fine if CAN0 has stopped receiving messages.I'll try increasing the stack.

author: Simon
author_rank: Unknown
timestamp: February 13, 2024, 09:18:51 am
content: Stack increase from what I assume was 4kB to 8kB did nothing. So in the ICSR the vector pending is 15, this is CAN0, which backs up what I just noticed that basically one CAN bus channel receiving is fine but not two.

author: Simon
author_rank: Unknown
timestamp: February 13, 2024, 09:59:39 am
content: Well i have it working. I am receiving and filtering one message on CAN0 and filtering one only on CAN1 although 5 arrive. The solution was to move the filter element i was using on CAN0 for the extended frame from element 0 to 1, not sure what is wrong here. Will look further.

author: Simon
author_rank: Unknown
timestamp: February 13, 2024, 10:15:09 am
content: Sorted, I have an array of memory address pointers so that each filter element can point to it's associated variable, when I added the extended ID's to the existing standard ID code I decided to use one array still and to offset the extended anes by the standard ones, I then stupidly got confused about the index starting at 0 and subtracted 1 from the number of standard ID's when adding there to the index of the extended ID, this meant that when I used extended filter element 0 with 0 standard filter elements I used index -1 and wrote to some random location.

author: ataradov
author_rank: Super Contributor
timestamp: February 13, 2024, 04:42:24 pm
content: And the way you solve those issues on the spot is by looking at the stack at the time exception happens. The stack would contain the following values:r0, r1, r2, r3, r12, lr, pc, psr. You are interested in PC, which would be the address of the instruction that caused the fault or close to it. Then you can match it to the source code location and know immediately what part of the C code is doing that.In more rare case, LR is also useful. Sometimes when the fault is caused by a jump to an incorrect location, PC will be that incorrect location. But LR would contain the address after the last successful branch and link instruction. And those are usually not too far away from the real fault place.