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

nrf_delay_us() is getting me a fatal error!

Hello, 

I'm currently developing a PS2 code to read the inputs of a mouse and transmit it over BLE, nrf_delay_us() is giving me a fatal error every time according to debug.

I tried the PS2 code only when developing the code and it worked flawlessly. but when I try to use it with the BLE HID mouse example it fails.

I think nrf_delays_us() is giving me those errors due to a timer being initialized (although not sure if that makes senso or not).

I would love to implement any other way of "waiting ", but I dont think I know how, maybe I should try to use the app_timer itself to generate the waiting? (300 microseconds is my biggest waiting time, but the code needs to follow a sequence).

Once again, thank you very much I trully appreciate all the effort.

Parents
  • Hakon, before I try to implement the FreeRTOS, you know how I can execute a function in between the advertising intervals?

    Maybe this can also be the solution i'm looking for. I think the function will only take 800 us in total, so maybe this is enough

  • See Multiprotocol support, the Radio Timeslot will guarantee that you are not interrupted by the SoftDevice. 

    What is it that you're trying to do exactly, writing to flash, interfacing with an external device, etc?

  • Your link actually gave me another great information on task I can run in between soft device activities! Thank you so much!

  • What is the PS/2 serial protocol spec? 

    Is it the MCU or mouse that controls the clock signal?

    What is the clock frequency? 


  • Clock signal is on behalf of MCU, it needs a clock from 10kHz~16kHz.

    Let me paste here the code I'm currently using, it works perfectly without BLE, maybe It will help you understand what I'm currently doing, but I'm not even setting up a continuous clock signal. (the Mouse keeps printing unsynced data over and over if I just feed it with clock and operate the data bus, it easier to do it sequentially [at least according to my tests so far])

    #include "PS2Mouse.h"
    
    //const uint8_t mask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
    
    static bool waitClockUp() {
      for(int i = 0; isClockState(); i++) {
        if(i > 20000)
          return false;
      }
      return true;
    }
     
    static bool waitClockDown() {
      for(int i = 0; !isClockState(); i++) {
        if(i > 20000)
          return false;
      }
      return true;
    }
    
    /** @brief Set a output state for Clock
     *  @param state : true is set, false is clear
     */
    void clockState(bool state) {
      nrf_gpio_cfg_output(CLOCK);
    
      state ? nrf_gpio_pin_set(CLOCK) : nrf_gpio_pin_clear(CLOCK);
    }
    
    /** @brief Get Clock Input 
     *  @returns Clock state
     */
    bool isClockState() {
      nrf_gpio_cfg_input(CLOCK, NRF_GPIO_PIN_PULLUP);
      nrf_delay_us(20);
      return nrf_gpio_pin_read(CLOCK);
    }
    
    /** @brief Set a output state for Data
     *  @param state : true is set, false is clear
     */
    void dataState(bool state) {
      nrf_gpio_cfg_output(DATA);
    
      state ? nrf_gpio_pin_set(DATA) : nrf_gpio_pin_clear(DATA);
    }
    
    /** @brief Get Data Input
     *  @returns Data state
     */
    bool isDataState() {
      nrf_gpio_cfg_input(DATA, NRF_GPIO_PIN_PULLUP);
      nrf_delay_us(20);
      return nrf_gpio_pin_read(DATA);
    }
    
    /** @brief Check oddParity
     *  @param byte : Check if the byte has it
     *  @returns The result
     */
    uint8_t oddParity(uint8_t byte) {
      uint8_t count = 0;
    
      for (uint8_t i = 0; i < 8; i++) {
        if (mask[i] & byte) count++;
      }
    
      return ((count + 1) % 2);
    }
    
    /** @brief Set device to Host-to-Device Mode
     *  @details This should be used to start a communication with
     *  the mouse.
     */
    void requestHostDevice() {
      /* Get into requestHostDevice Mode */
      clockState(set);
      dataState(set);
      nrf_delay_us(50);
      if(!waitClockUp()) return;
      if(!waitClockDown()) return;
    }
    
    /** @brief Starts a write transmission
     * 
     */
    void requestWriteMode() {
      /* Enter on Write Mode */
      dataState(set);
      clockState(set);
      nrf_delay_us(300);
      clockState(clear);
      nrf_delay_us(300);
      dataState(clear);
      nrf_delay_us(10);
      clockState(set);
    }
    
    /** @brief Wait on Clock to Toggle
     *  @details Use this to separate data bits
     */
    void waitClockToggle() {
      /* Wait for High on clock */
      if(!waitClockDown()) return;
      /* Wait for Low on clock */
      if(!waitClockUp()) return;
    }
    
    void writeMouse(uint8_t cmd) {
      uint8_t parity = 1;
    
      requestWriteMode();
    
      if(!waitClockUp()) return;
    
      for (int i = 0; i < 8; i++) {
        /* Set output based on Command and Mask */
        if (cmd & 0x01) {
          dataState(set);
        } else {
          dataState(clear);
        }
    
        waitClockToggle();
        parity = parity ^ (cmd & 0x01);
        cmd = cmd >> 1;
      }
    
      /* Set the parity */
      if(parity) {
        dataState(set);
      } else {
        dataState(clear);
      }
    
      /* Release data line */
      waitClockToggle();
      dataState(set);
      nrf_delay_us(50);
      if(!waitClockUp()) return;
      if(!waitClockDown()) return;
      //while(!isClockState() || !isDataState());
    
      clockState(clear);
      /* end */
    
    }
    
    
    
    uint8_t initMouse() {
      //uint8_t temp_ID_device;
      //uint8_t time = 90;
      uint8_t err_code;
      uint8_t counter = 0;
    
      err_code = sendCommand(0xFF);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      err_code = readMouse();
      if(err_code != 0xAA) {
        NRF_LOG_INFO("Self Test Fail -> 0x%X", err_code);
      }
      err_code = readMouse();
      NRF_LOG_INFO("Mouse ID -> 0x%X", err_code);
      counter++;
      nrf_delay_ms(5);
    
      err_code = sendCommand(0xFF);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      err_code = readMouse();
      if(err_code != 0xAA) {
        NRF_LOG_INFO("Self Test Fail -> 0x%X", err_code);
      }
      err_code = readMouse();
      NRF_LOG_INFO("Mouse ID -> 0x%X", err_code);
      counter++;
      nrf_delay_ms(5);
    
      err_code = sendCommand(0xFF);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      err_code = readMouse();
      if(err_code != 0xAA) {
        NRF_LOG_INFO("Self Test Fail -> 0x%X", err_code);
      }
      err_code = readMouse();
      NRF_LOG_INFO("Mouse ID -> 0x%X", err_code);
      counter++;
      nrf_delay_ms(5); 
      
      err_code = sendCommand(0xF3);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5); 
    
      err_code = sendCommand(0xC8);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5); 
    
      err_code = sendCommand(0xF3);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5); 
    
      err_code = sendCommand(0x64);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5);
    
      err_code = sendCommand(0xF3);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5); 
    
      err_code = sendCommand(0x50);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5);  
      
      err_code = sendCommand(0xF2);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5); 
    
      err_code = readMouse();
      NRF_LOG_INFO("Mouse ID -> 0x%X", err_code);
      counter++;
      nrf_delay_ms(5); 
    
      err_code = sendCommand(0xF4);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("%d Error -> 0x%X", counter, err_code);
        return err_code;
      }
      counter++;
      nrf_delay_ms(5); 
      
      return err_code;
    }
    
    /**
     * @brief Read byte from trackBall
     * @returns data byte
     * @details figure this out.
     */
    uint8_t readMouse() {
    
      uint8_t data = 0x00;
      uint8_t bit = 0x01;
    
      requestHostDevice();
      
      for (int i = 0; i < 8; i++) {
        if(!waitClockUp()) return 0xFE;
        if(isDataState()) {
          data = data | bit;
        }
        
        if(!waitClockDown()) return 0xFE;
        //waitClockToggle();
        bit = bit << 1;
      }
      
     
      if(!waitClockUp()) return 0xFE;
      if(!waitClockDown()) return 0xFE;
      if(!waitClockUp()) return 0xFE;
      if(!waitClockDown()) return 0xFE;
      clockState(clear);
      
      return data;
    }
    
    uint8_t sendCommand(uint8_t cmd) {
      uint8_t response;
      writeMouse(cmd);
      response = readMouse();
      if(response != 0xFE) {
        return response;
      }
      NRF_LOG_INFO("Error - > 0x%X", response);
      nrf_delay_us(120);
      response = sendCommand(cmd);
      return response;
    
    }
    
    
    
    mouse_loc_t askInput() {
      mouse_loc_t mouse;
    
      int err_code = sendCommand(0xEB);
      if(err_code != 0xFA) {
        NRF_LOG_INFO("Error -> 0x%X", err_code);
        return mouse;
      }     
      mouse.mstat = readMouse();
      mouse.mx = readMouse();
      mouse.my = readMouse();
    
      /* send the data back up */
      
      return mouse;
    }


    Important information that might help you in (since you are interested), 0xFA from mouse means ACK, and that's pretty much what we should expect from the mouse when sending settings. 0xFE from mouse means "send it again" and the rest is basically mouse id, status, delta X and delta Y.

    I'm up to any suggestions at this point.

    void setupClock() {
      /* Set the GPIO */
      nrf_gpio_cfg_output(18);
      /* Starts the Clock */
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      /* Wait for the Clock to start */
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
        ;
      /* Clear the event */
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
      /* Configure the Clock */
      NRF_GPIOTE->CONFIG[0] = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                              GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                              18 << GPIOTE_CONFIG_PSEL_Pos |
                              GPIOTE_CONFIG_OUTINIT_Low << GPIOTE_CONFIG_OUTINIT_Pos;
    
      //Configure timer
      NRF_TIMER1->PRESCALER = 0;
      NRF_TIMER1->CC[0] = 600;  // Adjust the output frequency by adjusting the CC.
      NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Enabled << TIMER_SHORTS_COMPARE0_CLEAR_Pos;
      NRF_TIMER1->TASKS_START = 1;
    
      //Configure PPI
      NRF_PPI->CH[0].EEP = (uint32_t)&NRF_TIMER1->EVENTS_COMPARE[0];
      NRF_PPI->CH[0].TEP = (uint32_t)&NRF_GPIOTE->TASKS_OUT[0];
    
      NRF_PPI->CHENSET = PPI_CHENSET_CH0_Enabled << PPI_CHENSET_CH0_Pos;
    }
    
    void startClock() {
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0) {
      }
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
    
      NRF_TIMER1->TASKS_START = 1;
    }


    I used this code to generate the clock back when I was using it.

    and once again, thank you for the interest.

  • Your rortocol needs to run in a Timeslot unless you also automate the data R/W with TIMER and GPIOTE.

  • I placed on a Timer at the beginning yes, but just a regular repeat timer and yet I was facing problems,

    Pardon my lack of understanding but what is a Timeslot?

Reply Children
Related