Forum Rule: Always post complete source code & details to reproduce any issue!
Page 11 of 11 FirstFirst ... 9 10 11
Results 251 to 259 of 259

Thread: FlexCAN_T4 - FlexCAN for Teensy 4

  1. #251
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,319
    thats weird, I just left the house and it was working using the 2 sketches posted, ill check it again when i get home from work

  2. #252
    Junior Member
    Join Date
    Mar 2020
    Posts
    18
    When you said try with my code, I thought you meant the code I posted. Using your reduced version of my code, it does work. However, with a serial.print in the flexcan_interrupt() function, it loops forever after the first call. Because every message RX and TX is being handled by the VCAN ISR, it works out in your version.

    When running the code I posted, this causes the code to stop responding, since the code can never get to the LCAN's ISR to transmit the next message.

    Comparing update3 and update4, you relocated the clear iflag line towards the end of the function. After successful transmission, if the txBuffer is empty, the flag will never be cleared before continuing to next MB.

    If I move the clear iflag line back to where it was in update3, it functions properly.
    Code:
        if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_TX_INACTIVE ) {
          if (!(imask & (1ULL << mb_num))) writeIMASKBit(mb_num); /* enable interrupt for MB if not enabled */
          
          writeIFLAGBit(mb_num); /* clear IFLAG  <--- this line  */
          if ( !txBuffer.size() ) continue; /* no queues available, continue next mailbox check */

  3. #253
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,319
    only reason i moved it was because something was throwing off between sequential or remote frames, but that may have been fixed somewhere else or that line was necessary, Im testing 3 types to make sure itll work. so with the last update4 and the edit above, it's fine? if so i will need to test it later against seq, normal, and remote frames, for consistancy

  4. #254
    Junior Member
    Join Date
    Mar 2020
    Posts
    18
    After more testing of Update4 with the edit above, it still requires LCAN.events() to keep outgoing traffic. It fixes the ISR getting stuck looping, but something else still requires events() to avoid overrunning the TX queue.

  5. #255
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,319
    yes this is why these are tests for new update later on, thats why I didn't want to touch the repo, I'm a bit busy this week but I'll try to work on it more

  6. #256
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,319
    I reverted the interrupt transmits as it wasn't stable compared to the loop, and made all transmits not able to occupy a mailbox into the TX queue, not just sequential ones. Loopback mode and wake up mode have been kept intact.
    So we are back to using events().

    specific mailboxes are queued if not able to send, unlike the old method which included a 100ms blocking timeout. events() will retain the mailbox to send when available without the 100ms block.
    sequential frames work as before, absolute first mailbox, queued if not sent
    any other writes go to any found TX mailbox, if none found

    Code:
    update5.zip

  7. #257
    Junior Member
    Join Date
    Mar 2020
    Posts
    18
    I believe I just found the source of the interrupt based instabilities. I think it's due to new interrupts being fired while flexcan_interrupt() is in process (due to a call from events()).
    To test this theory, I tried clearing imask at the beginning of flexcan_interrupt() and resetting at the end.

    After making the following 4 changes to flexcan_interrupt(), Update4 has performed well.

    Code:
    FCTP_FUNC void FCTP_OPT::flexcan_interrupt() {
      CAN_message_t msg; // setup a temporary storage buffer
      uint64_t imask = readIMASK(), iflag = readIFLAG();
      writeIMASK(0ULL); /* Added by MSADIE - prevent preemption by FlexCAN (I think!?) */
      
      if ( !(FLEXCANb_MCR(_bus) & (1UL << 15)) ) { /* if DMA is disabled, ONLY THEN you can handle FIFO in ISR */
        if ( (FLEXCANb_MCR(_bus) & FLEXCAN_MCR_FEN) && (imask & FLEXCAN_IMASK1_BUF5M) && (iflag & FLEXCAN_IFLAG1_BUF5I) ) { /* FIFO is enabled, capture frames if triggered */
          volatile uint32_t *mbxAddr = &(*(volatile uint32_t*)(_bus + 0x80 + (0 * 0x10)));
          uint32_t code = mbxAddr[0];
          msg.len = (code & 0xF0000) >> 16;
          msg.flags.remote = (bool)(code & (1UL << 20));
          msg.flags.extended = (bool)(code & (1UL << 21));
          msg.timestamp = code & 0xFFFF;
          msg.id = (mbxAddr[1] & 0x1FFFFFFF) >> ((msg.flags.extended) ? 0 : 18);
          msg.idhit = code >> 23;
          for ( uint8_t i = 0; i < (8 >> 2); i++ ) for ( int8_t d = 0; d < 4 ; d++ ) msg.buf[(4 * i) + 3 - d] = (uint8_t)(mbxAddr[2 + i] >> (8 * d));
          msg.bus = busNumber;
          msg.mb = FIFO; /* store the mailbox the message came from (for callback reference) */
          (void)FLEXCANb_TIMER(_bus);
          writeIFLAGBit(5); /* clear FIFO bit only! */
          if ( iflag & FLEXCAN_IFLAG1_BUF6I ) writeIFLAGBit(6); /* clear FIFO bit only! */
          if ( iflag & FLEXCAN_IFLAG1_BUF7I ) writeIFLAGBit(7); /* clear FIFO bit only! */
          frame_distribution(msg);
          ext_output1(msg);
          ext_output2(msg);
          ext_output3(msg);
          if (fifo_filter_match(msg.id)) struct2queueRx(msg);
        }
      }
    
      uint8_t exit_point = 64 - __builtin_clzll(iflag | 1); /* break from MSB's if unset, add 1 to prevent undefined behaviour in clz for 0 check */
      int8_t first_tx_found = -1;
    
      for ( uint8_t mb_num = mailboxOffset(); mb_num < FLEXCANb_MAXMB_SIZE(_bus); mb_num++ ) {
    
        if ( !txBuffer.size() ) { /* if transmits exist, don't skip any mailboxes */
          if ( mb_num >= exit_point ) break; /* early exit from higher unflagged mailboxes */
          if (!(imask & (1ULL << mb_num))) continue; /* don't read non-interrupt mailboxes */
          if (!(iflag & (1ULL << mb_num))) continue; /* don't read unflagged mailboxes */
        }
    
        volatile uint32_t *mbxAddr = &(*(volatile uint32_t*)(_bus + 0x80 + (mb_num * 0x10)));
        uint32_t code = mbxAddr[0];
    
        if ( (FLEXCAN_get_code(code) >> 3) && (first_tx_found == -1) ) first_tx_found = mb_num; /* set absolute first TX mailbox found */
    
        if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_EMPTY ) {
          /* there are no flags for EMPTY reception boxes, however, when sending remote
             frames, the mailboxes switch to RX_EMPTY and trigger the flag */
          if (!(iflag & (1ULL << mb_num))) continue; /* only process the flagged RX_EMPTY mailboxes */
          writeIFLAGBit(mb_num); /* clear IFLAG */
          mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE);
        }
    
        if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_TX_INACTIVE ) {
          if (!(imask & (1ULL << mb_num))) {	
            imask |= (1ULL << mb_num); /* enable interrupt for MB if not enabled */
          }		/* Changed by MSADIE - enable via "imask" instead of "writeIMASKBit()"*/
          
          if ( !txBuffer.size() ) {
            writeIFLAGBit(mb_num); /* Added by MSADIE - clear IFLAG */
            /* This fixes what I believe is an unrelated bug */
            continue; /* no queues available, continue next mailbox check */
          }
          
          uint8_t buf[sizeof(CAN_message_t)];
          txBuffer.peek_front(buf, sizeof(CAN_message_t));
          memmove(&msg, buf, sizeof(msg));
    		
          if ( (msg.seq) && (mb_num != first_tx_found) && (!msg.flags.remote) ) continue; /* only offload sequential frames to absolute first mailbox */
          else if ( msg.mb == -1 ); /* write to any available mailbox */
          else if ( msg.mb == mb_num ); /* write to a specific mailbox */
          else continue; /* if it didn't pass last condition, it is not the specific mailbox, keep scanning till then */
          
          /* if transmitting sequential frames, don't assume pending remote frame transmissions
             arn't processing, otherwise the swap to RX_EMPTY would cause the next MB to transmit
             the sequential, essentially consuming 2 mailboxes for sequential writes. This prevents
             this issue by checking next cycle after current transmissions in the status register */
          if ( msg.seq && FLEXCANb_ESR1(_bus) & (1UL << 6) ) continue;
          
          txBuffer.pop_front(); /* clear on write */
          
          writeIFLAGBit(mb_num); /* clear IFLAG */
          mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_INACTIVE);
          mbxAddr[1] = (( msg.flags.extended ) ? ( msg.id & FLEXCAN_MB_ID_EXT_MASK ) : FLEXCAN_MB_ID_IDSTD(msg.id));
          code = msg.len << 16;
          if ( msg.flags.remote ) code |= (1UL << 20);
          if ( msg.flags.extended ) code |= (3UL << 21);
          for ( uint8_t i = 0; i < (8 >> 2); i++ ) mbxAddr[2 + i] = (msg.buf[0 + i * 4] << 24) | (msg.buf[1 + i * 4] << 16) | (msg.buf[2 + i * 4] << 8) | msg.buf[3 + i * 4];
          mbxAddr[0] = code | FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_TX_ONCE);
        }
    
        else if ( ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_FULL ) ||
             ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_OVERRUN ) ) {
    
          /* treat receptions normally if transmit queue exists */
          if (!(imask & (1ULL << mb_num))) continue; /* don't read non-interrupt mailboxes */
          if (!(iflag & (1ULL << mb_num))) continue; /* don't read unflagged mailboxes */
    
          msg.flags.extended = (bool)(code & (1UL << 21));
          msg.id = (mbxAddr[1] & 0x1FFFFFFF) >> ((msg.flags.extended) ? 0 : 18);
          if ( FLEXCAN_get_code(code) == FLEXCAN_MB_CODE_RX_OVERRUN ) msg.flags.overrun = 1;
          msg.len = (code & 0xF0000) >> 16;
          msg.mb = mb_num;
          msg.timestamp = code & 0xFFFF;
          msg.bus = busNumber;
          for ( uint8_t i = 0; i < (8 >> 2); i++ ) for ( int8_t d = 0; d < 4 ; d++ ) msg.buf[(4 * i) + 3 - d] = (uint8_t)(mbxAddr[2 + i] >> (8 * d));
          mbxAddr[0] = FLEXCAN_MB_CS_CODE(FLEXCAN_MB_CODE_RX_EMPTY) | ((msg.flags.extended) ? (FLEXCAN_MB_CS_SRR | FLEXCAN_MB_CS_IDE) : 0);
          (void)FLEXCANb_TIMER(_bus);
          writeIFLAGBit(mb_num);
          if ( filter_match((FLEXCAN_MAILBOX)mb_num, msg.id) ) struct2queueRx(msg); /* store frame in queue */
          frame_distribution(msg);
          ext_output1(msg);
          ext_output2(msg);
          ext_output3(msg);
        }
      }
    
      FLEXCANb_ESR1(_bus) |= FLEXCANb_ESR1(_bus);
      asm volatile ("dsb");
      writeIMASK(imask); /* Added by MSADIE disable new interrupts */
    }
    Files:

  8. #258
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,319
    no dont do that, that puts the controller in HALT mode, the imask bits need to stop the controller to change them, and you also disabled any mailbox interrupts as well

    events() wasnt used during my tests, so it can be crossed out of being a cause.

    the imask bit tells the controller what mailboxes are interrupt enabled, disabling them causes reception to drop to polling mode, plus cycling the flexcan in freeze mode for the imask bits will cause frames to go missing during that phase

    the other thing i realized is if we want to issue a frame we want it done right away in write() with events() as a backup for the TX queues, rather than causing more latency in the ISR.

    I think we should stick with what we have now without adding more overhead and extra mailbox scans into the ISR. If I can manage to meet the ISR half way with events() without extra scans to mailboxes, it would be okay, but right now as it stands the transmit interrupts were unstable and caused extra ISR overhead, plus playing with the imasks causes confusion while cycling the controller that may miss frames.
    Last edited by tonton81; Today at 10:48 AM.

  9. #259
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,319
    Here is a new test of transmit interrupts! redesigned starting from the github copy. Transmit interrupts are enforced now, there is no way to disable them without breaking isr & loop handling of TX queues. Test ran without events().
    Not using events(), RX interrupts fire directly to callback, no RX queues. Doesn't participate in TX dequeues.
    Using events(), RX queue is pushed to callback from loop, and loop() works with ISR for offloading TX queues, as a safety measure, the NVIC IRQ is disabled and enabled if the events() dequeue happens before the ISR, to prevent potential race conditions.

    Code:
    update6.zip
    Last edited by tonton81; Today at 01:10 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •