This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Non - blocking delay between SPI transfers for LED Screen graphic effects

Hi,

Good Day!

Problem: We have LED Screen connected to nrf52832 through SPI com and we have some led graphic effects in our application which requires some delay between SPI transfers to the display (softdevice is used in our application). Figured out that using nrf_delay_ms() function will not work effectively. 

Query:

How to implement a delay between SPI TXfers in non-blocking mode and which is also safe to use with the softdevice? Had a hard time implementing it with app_timer, because for SPI transfers we need to send the data and app_timerout_handler does not take any input arguments which is obvious. 

Kindly share your insights and help us solve this issue.

Thank you,
Aim High

Parents
  • Had a hard time implementing it with app_timer, because for SPI transfers we need to send the data and app_timerout_handler does not take any input arguments

    I don't follow that.

    For async delays, you need a timer.

    A State Machine (aka FSM - "Finite State Machine") would seem like an obvious choice here to manage what you're doing on the SPI ...

    https://www.avrfreaks.net/comment/1145276#comment-1145276

  • Hi,

    Ok, I try to explain what I meant by a hard time using app_timer. 

    For example, A string to be printed on the screen whose string length is out of screen boundaries. One solution to print the complete string is to scroll right to left at the same time this scroll effect should be compatible with the human eye refresh rate say around 150 frames per second.

    We are using HT1632 LED driver IC uses SPI protocol and each transaction needs address and data to be sent. Initially used nrf_delay_ms for the scroll effect of 150ms per frame.  That means SPI transfer has to be done at every 150mSec till it reaches the scroll count. 

    For this reason, we tried to use app_timer to trigger SPI transactions every 150mSec in app_timer_out_handler(). But had a problem because the string data is churned through for() loop. Once for every data app_timer_start is called, before it hits the app_timer_out_handler() the for() loop is continued to execute. 

    Now this is implemented using app_timer, but using some flags, while() loop and __WFE() or WFI(). Not sure if this will work as expected when the complete system is integrated.

    Attached part of the code, for which this app_timer is used for the delay effect.

    So please share your thoughts on using the __WFE() or WFI() after the app_timer_start() is called in a while loop? Is this actually blocking the CPU time? If not, if any event occurs will it come back to the same point after that event is taken care of? 

    void led_print_msg(char c, uint8_t msg_len) {
    
      uint8_t Char_Index;
      uint8_t ColData_A, ColData_B;
      uint8_t Col_length, i, k;
      uint16_t j;
    
      if (c > 15) {
        /**Replace undisplayable characters with blank;**/
        if (c < 32 || c > 126) {
          Char_Index = 0;
        } else {
          Char_Index = c - 32; /**Regular characters**/
        }
    
        Col_length = Font5x21[Char_Index][3]; /**Get the number of colomns for the character**/
    
        for (uint8_t col = 0; col < Col_length; col++) {
    
          ColData_A = Font5x21[Char_Index][col];
          ColData_B = ColData_A >> 4;
    
          for (i = 0; i < 2; i++) { /**Store character data into array[RowA][RowB]!**/
            if (i == 0) {
              temp_array[col + Char_Inx_Accm][0] = ColData_A;
            } else if (i == 1) {
              temp_array[col + Char_Inx_Accm][1] = ColData_B;
            }
          }
        }
      }
      Char_Inx_Accm += Col_length;
      transfer_length++;
    
      /**
      Start LED module SPI trasnfer after string is captured into data matrix
      **/
      if (transfer_length == msg_len) {
    
        if (transfer_length > CHAR_FIT_SCRN) {
    
          /** Not so accurate to find frame count for varying character width 
         frame_count = ((transfer_length - CHAR_FIT_SCRN)*MAX_CHAR_SIZE*MAX_ROW)- ((white_spc-1)*2*MAX_ROW);  /**Calculates the number of frames to shift the complete data**/
    
          /**Accurate method to find the frame count of the string message.**/
          frame_count = (Char_Inx_Accm - MAX_ROW_PRINT_MESSAGE) * MAX_ROW;
    
        } else {
          frame_count = CHAR_FIT_SCRN * MAX_CHAR_SIZE;
        }
    
        /**Requires a function to scroll message from right to left if the (Char_Inx_Acc) exceeds 21**/
    
        /**app_timer or PPI should be used to add the appropriate delay in the function.**/
        
        
        for (j = 0; j < frame_count; j++) {
    
          if (incr >= RAM_HIGH_ADD) {
    
            row_offset++;           /** Initialize after every print message.**/
            incr = 0;
            row_incr = row_offset; /** Initialize after every print message.**/
    
            //nrf_delay_ms(190);
            
            /**This is where it is replaced with the app_timer to delay effect.**/
            ret_code_t err_code = app_timer_start(m_slb_led_timer, APP_TIMER_TICKS(SLB_LED_SCROLL_RL), NULL);
            APP_ERROR_CHECK(err_code);
    
            /**While app_time_out_handler does nothing, expect the to update the spi transaction flag.*/
            
            while(!LED_PRINT_MSG_FLAG){
            
            __WFE();                   /*Will it work?.*/
            __WFI();
            }
            LED_PRINT_MSG_FLAG = false;
          }
    
          else {
            for (k = 0; k < 2; k++) {
              
              LED_RAM_ADDRESS = incr;
              LED_RAM_DATA    = temp_array[row_incr][k];
              led_write_data(incr, temp_array[row_incr][k]);
              //ret_code_t err_code = app_timer_start(m_slb_led_timer, APP_TIMER_TICKS(SLB_LED_SCROLL_RL), NULL);
              //APP_ERROR_CHECK(err_code);
              incr++;
            }
            row_incr++;
          }
        }
        app_timer_stop(m_slb_led_timer);
        transfer_length = CONSTANT_ONE; /**reset all the flags and matrices**/
        Char_Inx_Accm = 0;
        frame_count = 0;
        row_offset = 0;
        row_incr = 0;
        memset(temp_array, 0, sizeof(temp_array));
      }
    }
    

  • I thought you said you wanted the delay to be asynchronous - ie, not in-line?

Reply Children
  • Hi,

    I am not sure if we wanted async call to the function with a delay. 

    Let me try to explain once more time when led_print_function is called and it takes some time to print all the messages. Don't mind if you find this as an elementary question When led_print_fun is a busy printing message on the screen and suppose at the same time there was an external interrupt( with high priority) to be served. then would this stop the led_print function and come back after the external interrupt is served? 

    Thank you

Related