[SPIM + NUS] conflict between the SPIM and BLE thread.

I am programming with the nRF52840DKs. [Toolchain Manager: v1.3.0, IDE: Visual Studio Code (VSCode), SDK: ncs v2.6.0, window11 pro]

I am currently working on integrating 'NUS_peripheral' and 'SPIM'.

My goal: communicate with the ADC via SPIM and transmit the collected data via Bluetooth.

To briefly explain my code, the SPIM turns on and off at regular intervals using a timer. The NUS (peripheral) sends data through a while loop.

However, it seems that there's a conflict between the SPIM and the while loop in the BLE thread.

Below are the main code:

#define MTU_SIZE 244
#define PRIORITY 7

nrfx_spim_t spim1_inst = NRFX_SPIM_INSTANCE(SPIM_INST_IDX);
nrfx_timer_t timer1_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX);
nrfx_gpiote_t gpiote_inst = NRFX_GPIOTE_INSTANCE(GPIOTE_INST_IDX);
nrf_ppi_channel_t ppi_channel_spi_start;
nrf_ppi_channel_t ppi_channel_spi_end;

volatile uint16_t initialization_counter = 0;
volatile uint16_t repeat_counter = 0;
volatile uint16_t NUS_send_counter = 0;
volatile bool initialization_stop = false;

#define TIME_TO_WAIT_US 50

uint8_t spim_tx_buf_initial[30][2];
uint8_t spim_tx_buf_repeat[18][2];

#define rx_data_size 4096
uint8_t spim_rx_buf_A[rx_data_size][2];
uint8_t spim_rx_buf_B[rx_data_size][2];
uint8_t (*spim_buffer)[2];
uint8_t (*nus_buffer)[2];
uint8_t out_channel;

void spim1_handler(nrfx_spim_evt_t const * p_event, void * p_context) {   
   NUS_send_counter++;
    
   if(!initialization_stop){
         initialization_counter++;
         if(initialization_counter == 30){
            initialization_stop = true;
            spim1_inst.p_reg->TXD.PTR = (uint32_t)spim_tx_buf_repeat[0];
         }
      return ;
   }
   repeat_counter++;
   if ( repeat_counter % 18 == 0 ) {
      spim1_inst.p_reg->TXD.PTR = (uint32_t)spim_tx_buf_repeat[0];
   } 
}

void timer0_handler(nrf_timer_event_t event_type, void * p_context){   

} 

void peripheral_setup(void){
    nrfx_err_t error;
    (void)error;
    
    /*  GPIOTE Setting */
    static const nrfx_gpiote_output_config_t output_config = {
        .drive = NRF_GPIO_PIN_S0S1,
        .input_connect = NRF_GPIO_PIN_INPUT_DISCONNECT,
        .pull = NRF_GPIO_PIN_NOPULL,
    };
    const nrfx_gpiote_task_config_t task_config = {
        .task_ch = out_channel,
        .polarity = NRF_GPIOTE_POLARITY_TOGGLE,
        .init_val = NRF_GPIOTE_INITIAL_VALUE_HIGH,
    };

    error = nrfx_gpiote_output_configure(&gpiote_inst, SS_PIN_MASTER, &output_config, &task_config);
    nrfx_gpiote_out_task_enable(&gpiote_inst, SS_PIN_MASTER);

    /*  SPIM 1 Setting */
    nrfx_spim_config_t spim1_config = NRFX_SPIM_DEFAULT_CONFIG(SCK_PIN_MASTER,
                                                            MOSI_PIN_MASTER,
                                                            MISO_PIN_MASTER,
                                                            NRF_SPIM_PIN_NOT_CONNECTED);
    spim1_config.frequency      = NRFX_MHZ_TO_HZ(8);
    error = nrfx_spim_init(&spim1_inst, &spim1_config, spim1_handler,0);

    nrfx_spim_xfer_desc_t spim1_xfer_desc = NRFX_SPIM_XFER_TRX((uint8_t*)spim_tx_buf_initial, 2, (uint8_t*)spim_rx_buf_A, 2);
    uint32_t spim1_flags = NRFX_SPIM_FLAG_HOLD_XFER | NRFX_SPIM_FLAG_REPEATED_XFER; 
    error = nrfx_spim_xfer(&spim1_inst, &spim1_xfer_desc, spim1_flags);
    spim1_inst.p_reg->TXD.PTR = (uint32_t)spim_tx_buf_initial[0];
    spim1_inst.p_reg->TXD.MAXCNT = 2;
    spim1_inst.p_reg->TXD.LIST =SPIM_TXD_LIST_LIST_ArrayList << SPIM_TXD_LIST_LIST_Pos;
    spim1_inst.p_reg->RXD.PTR = (uint32_t)spim_rx_buf_A[0];
    spim1_inst.p_reg->RXD.MAXCNT = 2;
    spim1_inst.p_reg->RXD.LIST = SPIM_RXD_LIST_LIST_ArrayList << SPIM_RXD_LIST_LIST_Pos;

    /*  TIMER 0 Setting */
    nrfx_timer_config_t timer0_config = NRFX_TIMER_DEFAULT_CONFIG(16000000);
    timer0_config.bit_width          = NRF_TIMER_BIT_WIDTH_32,
    error = nrfx_timer_init(&timer1_inst, &timer0_config, timer0_handler);
    //error = nrfx_timer_init(&timer1_inst, &timer0_config, NULL);
    nrfx_timer_clear(&timer1_inst);
    k_sleep(K_MSEC(2000));


    uint32_t desired_ticks = nrfx_timer_us_to_ticks(&timer1_inst, TIME_TO_WAIT_US);
    nrfx_timer_extended_compare(&timer1_inst, NRF_TIMER_CC_CHANNEL0, desired_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true);

    /*   PPI  Setting  */
    uint32_t gpiote_task_addr = nrfx_gpiote_out_task_address_get(&gpiote_inst ,SS_PIN_MASTER);    
    uint32_t timer_start_compare_event_addr = nrfx_timer_compare_event_address_get(&timer1_inst, NRF_TIMER_CC_CHANNEL0);
    uint32_t spi_start_task_addr   = nrfx_spim_start_task_address_get(&spim1_inst);
    uint32_t spi_end_evt_addr = nrfx_spim_end_event_address_get(&spim1_inst);

    // Timer reaches the desired tick -> GPIOTE toggle(off), SPI start
    error = nrfx_gppi_channel_alloc(&ppi_channel_spi_start);
    nrfx_gppi_channel_endpoints_setup(ppi_channel_spi_start, timer_start_compare_event_addr, gpiote_task_addr);
    nrfx_gppi_fork_endpoint_setup(ppi_channel_spi_start, spi_start_task_addr);
    // SPI tx-rx transmission ends -> GPIOTE toggle(on)
    error = nrfx_gppi_channel_alloc(&ppi_channel_spi_end);
    nrfx_gppi_channel_endpoints_setup(ppi_channel_spi_end, spi_end_evt_addr, gpiote_task_addr);

}

void ble_write_thread(void){
   int ret;
   uint16_t temp;
   uint8_t (*temp_buffer)[2];
    
   k_sem_take(&nus_start, K_FOREVER);
   LOG_INF("Starting BLE Write Thread");

   while (1) {

      temp = NUS_send_counter;
      NUS_send_counter = 0;
      
      temp_buffer = spim_buffer;  
      spim_buffer = nus_buffer;
      nus_buffer = temp_buffer;

      spim1_inst.p_reg->RXD.PTR = (uint32_t)spim_buffer;

      while(temp > 0){
         if(temp < MTU_SIZE){
            ret = bt_nus_send(current_conn, (uint8_t *)nus_buffer, temp);
            temp = 0;
            break;
         }else{
            ret = bt_nus_send(current_conn, (uint8_t *)nus_buffer, MTU_SIZE);
            temp -= MTU_SIZE;
         }
      }
      if (k_sem_take(&disconnect_sem, K_NO_WAIT) == 0){
         LOG_INF("Disconnected, exiting BLE Write Thread");
         return;
      }
   }
}

K_THREAD_DEFINE(ble_write_thread_id, 8192, ble_write_thread, NULL, NULL, NULL, PRIORITY, 0, 0);

Parents
  • Hi Seongmin, 

    Could you elaborate more on the issue you are facing ? Please describe the issue in more detail. 

  • Assumption: 
    Task1: SPIM Communication
    Task2: SPIM Handler
    Task3: NUS_send (Executed in ‘ble_write_thread’)

    I would like the tasks to proceed as shown in the image below.

    The number of Task1 and Task2 executions before Task3 runs doesn't matter. However, it seems that the tasks are not running as expected. In particular, I suspect that the transition between buffers in the double-buffering process is not working smoothly. I have tried using semaphores, mutexes, and locks, but only encountered errors, which leads me to believe that I haven't used them correctly.

    Here is the code I’m using:

          temp_buffer = spim_buffer;  
          spim_buffer = nus_buffer;
          nus_buffer = temp_buffer;
    
          spim1_inst.p_reg->RXD.PTR = (uint32_t)spim_buffer;

Reply
  • Assumption: 
    Task1: SPIM Communication
    Task2: SPIM Handler
    Task3: NUS_send (Executed in ‘ble_write_thread’)

    I would like the tasks to proceed as shown in the image below.

    The number of Task1 and Task2 executions before Task3 runs doesn't matter. However, it seems that the tasks are not running as expected. In particular, I suspect that the transition between buffers in the double-buffering process is not working smoothly. I have tried using semaphores, mutexes, and locks, but only encountered errors, which leads me to believe that I haven't used them correctly.

    Here is the code I’m using:

          temp_buffer = spim_buffer;  
          spim_buffer = nus_buffer;
          nus_buffer = temp_buffer;
    
          spim1_inst.p_reg->RXD.PTR = (uint32_t)spim_buffer;

Children
Related