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

Merging SPI, TWI and Buttonless dfu

Hi Everyone

I am working on nrf52832 with sdk 14.0.0 on iar IDE.  TWI and SPI separately working fine in buttonless_dfu then i merged SPI and TWI in buttonless_dfu itself but due to adding both codes they stuck . .

i also try to change the priority( 2 , 3 or same) of both (TWI and SPI) and also enable the peripheral resouce sharing bit. 

  • Could you please describe in what way it is "stuck"? Does the code compile? Does it run, but you can't see anything on the SPI or TWI (or both), or does it crash due to an APP_ERROR_CHECK()? If you set a breakpoint on the last line before the for (;;) loop, does it hit, or does it stop before this? 

    Can you also try to define "DEBUG" in your preprocessor defines, set optimization to 0 (-O0), and set a breakpoint in app_error.c on line 73, and see if it breaks there?

    Best regards,

    Edvin

  • Hi Edvin,

    Thanks for reply, 

    We were using same instance of i2c and spi and same priority for both that causing device stuck. Now we are using twi0 and spi1 now it working and changed the priority also.

    Now the problem is as described below:

    in our application we are trying to write a chunk of 4.8k bytes to external spi flash w25q32fw (winbond flash), collected from sensors interfaced with I2C lines. The SPI behavior is very random as some time all the commands and data goes well into external flash and sometime it fails. It seems likes MOSI line is not working properly. We also debugged the issue on CRO and saw same behavior.

    The SPI code is as follows

    /**
    * Copyright (c) 2015 - 2017, Nordic Semiconductor ASA
    * 
    * All rights reserved.
    * 
    * Redistribution and use in source and binary forms, with or without modification,
    * are permitted provided that the following conditions are met:
    * 
    * 1. Redistributions of source code must retain the above copyright notice, this
    *    list of conditions and the following disclaimer.
    * 
    * 2. Redistributions in binary form, except as embedded into a Nordic
    *    Semiconductor ASA integrated circuit in a product or a software update for
    *    such product, must reproduce the above copyright notice, this list of
    *    conditions and the following disclaimer in the documentation and/or other
    *    materials provided with the distribution.
    * 
    * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
    *    contributors may be used to endorse or promote products derived from this
    *    software without specific prior written permission.
    * 
    * 4. This software, with or without modification, must only be used with a
    *    Nordic Semiconductor ASA integrated circuit.
    * 
    * 5. Any software provided in binary form under this license must not be reverse
    *    engineered, decompiled, modified and/or disassembled.
    * 
    * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
    * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
    * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
    * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
    * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    * 
    */
    
    
    #include "spi_flash.h"
    #include "sensor_nrf.h"
    
    #define SPI_INSTANCE  1 /**< SPI instance index. */
    
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    //static uint16_t curr_page = 1;
    bool pageOverflow;
    //s_flash flash;
    
      uint16_t read_page = 0;
      uint8_t  read_index = 0; 
      uint16_t write_page = 0;
      uint8_t  write_index = 0;  
    
    
    uint32_t getFlashAddr(uint16_t page_number, uint8_t offset) 
    {
      uint32_t address =0;
      address = page_number << 8;
      address += offset;
      return address;
    }
    
    //Checks to see if pageOverflow is permitted and assists with determining next address to write to.
    uint8_t W25Q32_AddrCheck(uint32_t address)
    {
      if (address > 0x3FFFFF) 
      {
        if (!pageOverflow) 
        {
          return (1);
        }
        else
          return (2);  
      }
      else
        return (0);
    }
    
    /******************************************************************************
    * File Name : spi_flash.c
    * Function Name : 
    * Parameters : 
    * Return : 
    * Description : determine whether W25Q32 busy busy function returns 1
    *****************************************************************************/
    uint8_t W25Q32_BUSY (void) 
    {
      uint8_t flag = 0;
      uint8_t buf[1]={0};
      const uint8_t wBuff[] = {W25Q32_READ_STATUS_REG1};
      
      spi_xfer_done = false; 
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), buf, sizeof(buf)));  
      while (!spi_xfer_done)
      {
        __WFE();
      }
      
      flag = buf[0];
      
      flag &= 0x01;
      
      return flag;
    }
    
    
    uint8_t W25Q32_WEL(void) 
    {
      uint8_t flag = 0;
      uint8_t buf[1]={0};
      const uint8_t wBuff[] = {W25Q32_WRITE_ENABLE};
      
      spi_xfer_done = false; 
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), buf, sizeof(buf)));  
      while (!spi_xfer_done)
      {
        __WFE();
      }
      
      flag = buf[0];
      
      flag &= WRTEN;
      
      return flag;
    }
    
    /******************************************************************************
    * File Name : spi_flash.c
    * Function Name : 
    * Parameters : 
    * Return : 
    * Description : erase the entire chip
    *****************************************************************************/
    
    bool W25Q32_erase(uint16_t page_number, uint8_t offset, size_t length)
    {
      /* Note that Block erase might be more efficient when the floor map
      * is well planned for OTA but to simplify for the temporary implementation,
      * sector erase is used blindly. */
      uint8_t wBuf[4];
      uint8_t buf[1];
      uint32_t address;
      size_t i, numsectors;
      
      if(page_number >= TOTAL_PAGES || offset >= OFFSET_RANGE)
          return false;
      
      address = getFlashAddr(page_number, offset);
      
      wBuf[0] = W25Q32_SECTOR_ERASE;
       //wBuf[0] = BLS_CODE_ERASE_64K;
      
      {
        size_t endoffset = address + length-1;//offset + length - 1;
        address = (address / W25Q32_SECTOR_SIZE) * W25Q32_SECTOR_SIZE;
        numsectors = (endoffset - address + W25Q32_SECTOR_SIZE - 1) /
          W25Q32_SECTOR_SIZE;
      }
      
      
      for (i = 0; i < numsectors; i++)
      {
        /* Wait till previous erase/program operation completes */
        
    //   while((W25Q32_BUSY() == BUSY)&&(W25Q32_WEL() == WRTEN)); 
        while((W25Q32_BUSY() == BUSY));
        
        //nrf_delay_ms(1);
        
        W25Q32_WEL();
        
        wBuf[1] = (address >> 16) & 0xff;
        wBuf[2] = (address >> 8) & 0xff;
        wBuf[3] = address & 0xff;
        
        spi_xfer_done = false; 
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuf, sizeof(wBuf), buf, sizeof(buf)));  
        while (!spi_xfer_done)
        {
          __WFE();
        } 
        
        address += W25Q32_SECTOR_SIZE;
      }
      
      return true;
    }
    
    /******************************************************************************
    * File Name : spi_flash.c
    * Function Name : 
    * Parameters : 
    * Return : 
    * Description : write prohibit function
    *****************************************************************************/
    void Write_Disable(void) 
    {
      const uint8_t wBuff[1] = {W25Q32_DISABLE_ENABLE};
      uint8_t infoBuf[1]={0};
      //  uint8_t flag;
      spi_xfer_done = false;
      
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), infoBuf, sizeof(infoBuf)));
      
      while (!spi_xfer_done)
      {
        __WFE();
      }
      
      //  flag = infoBuf[0];
      //  
      //  flag &= WRTEN;
      //  
      //  return flag;
    }
    
    /******************************************************************************
    * File Name : spi_flash.c
    * Function Name : 
    * Parameters : 
    * Return : 
    * Description : write "len" bytes from "data" to "address" on W25Q32
    *****************************************************************************/
    bool W25Q32_writeBytes(uint16_t page_number, uint8_t offset, uint8_t* pdataBuff, size_t length)
    { 
      uint8_t buf[1]={0};
      uint8_t wBuff[255]={0}; 
      uint32_t address =0;
      size_t pgSize = 256;
      
    //  uint8_t byteCtr = 0;
      size_t ilen;
    //  ilen = 256-(offset%256);
    
      
      while (length > 0)
      {
        address = getFlashAddr(page_number, offset);
        
          ilen = 256-(offset%256);
    
        /* Wait till previous operation completes */
    //   while((W25Q32_BUSY() == BUSY)&&(W25Q32_WEL() != WRTEN));
        
       while((W25Q32_BUSY() == BUSY));
        
    //    nrf_delay_ms(1);
        
        W25Q32_WEL();
        
        if(length <ilen)
        {
          ilen = length;
          
          switch(ilen)
          {
          case 255:
            ilen = ilen-4;
            break;
          case 254:
            ilen = ilen-3;
            break;
          case 253:
            ilen = ilen-2;
            break;
          case 252:
            ilen = ilen-1;
            break; 
          default:
            ilen = length;
            break;
          }
        }    
        else
        {
          ilen = ilen-5;
        }
          
        wBuff[0] = W25Q32_PAGE_PROGRAM ; 
        wBuff[1] = (address >> 16)&0xff;
        wBuff[2] = (address >> 8)&0xff;
        wBuff[3] = (address)&0xff;
        
        memcpy(&wBuff[4], pdataBuff, ilen);
    
        spi_xfer_done = false; 
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), buf, sizeof(buf)));  
        while (!spi_xfer_done)
        {
          __WFE();
        } 
    
        pdataBuff += ilen;
    //    address += ilen;
        offset += ilen;
        length -= ilen;
    
        
    //    while(byteCtr != 255)
    //    {
    //      wBuff[byteCtr] = 0;
    //      byteCtr++;
    //    }
    //    byteCtr = 0;
           
        if((offset != 0)&&(length >0))
        { 
          uint8_t len2;
    
          len2 = pgSize - offset;
          
    //      W25Q32_Write (page_number, offset, pdataBuff, len2);
    
          offset += len2;
          page_number++;
    //      pdataBuff += len2;
    //      address += len2;
    //      length -= len2;
        }
      
    //    ilen = 256;
      }
      
      return true;
    }
    
    void W25Q32_Write(uint16_t page_number, uint8_t offset, uint8_t* pdataBuff, uint8_t len)
    {
      uint8_t wBuff[255]={0};
      uint8_t buf[1]={0};
      
      //  uint8_t* pArray[2] = {wBuff, pdataBuff}; 
      
      uint32_t address =0;
      
      address = getFlashAddr(page_number, offset);
      
      /* Wait till previous operation completes */
    //  while((W25Q32_BUSY() == BUSY)&&(W25Q32_WEL() == WRTEN)); 
       while((W25Q32_BUSY() == BUSY));
        
    //    nrf_delay_ms(1);
        
        W25Q32_WEL();
      
      wBuff[0] = W25Q32_PAGE_PROGRAM ; 
      wBuff[1] = (address >> 16)&0xff;
      wBuff[2] = (address >> 8)&0xff;
      wBuff[3] = (address)&0xff;
      
      //  uint8_t* pArray[2] = {wBuff, pdataBuff};
      memcpy(&wBuff[4], pdataBuff, len);
      
      spi_xfer_done = false; 
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), buf, sizeof(buf)));  
      while (!spi_xfer_done)
      {
        __WFE();
      } 
    }
    /******************************************************************************
    * File Name : spi_flash.c
    * Function Name : 
    * Parameters : 
    * Return : 
    * Description : read "len" bytes from "address" to "data" from W25Q32
    *****************************************************************************/
    bool W25Q32_readBytes(uint16_t page_number, uint8_t offset, uint8_t* pdataBuff , size_t length)
    {
      uint8_t wBuff[4]={0};
      uint8_t buf[255]={0};
    //  uint8_t byteCtr = 0;
      uint32_t address =0;
      size_t pgSize = 256;
      size_t ilen;// = 256-(offset%256);  // Force the first set of bytes to stay within the first page
      
      while(length>0)
      { 
        ilen = 256-(offset%256);
        
        address = getFlashAddr(page_number, offset);
    
        /* Wait till previous operation completes */
        Write_Disable(); 
        
        while ((W25Q32_BUSY() == BUSY));
        
        if(length<ilen)
        {
          ilen = length;
          switch(ilen)
          {
          case 255:
            ilen = ilen-4;
            break;
          case 254:
            ilen = ilen-3;
            break;
          case 253:
            ilen = ilen-2;
            break;
          case 252:
            ilen = ilen-1;
            break; 
          default:
            ilen = length;
            break;
          }
        }
        else
        {
          ilen = ilen-5;
        }
        
        wBuff[0] = W25Q32_READ_DATA;
        wBuff[1] = (address >> 16)&0xff;
        wBuff[2] = (address >> 8)&0xff;
        wBuff[3] = (address)&0xff;
        
        spi_xfer_done = false; 
        
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), buf, sizeof(buf)));  
        
        while (!spi_xfer_done)
        {
          __WFE();
        }
        
        memcpy(pdataBuff, &buf[4], ilen);
        pdataBuff += ilen;    
        offset += ilen;
        length -= ilen;
        ilen = pgSize - offset;
        
        if((ilen != 0)&&(length>0))
        {
               
    //      W25Q32_Read (page_number, offset, pdataBuff , ilen);
    
          offset += ilen;
          page_number++;
    //      pdataBuff += ilen;
    //      length -= ilen;
          ilen = 0;
        }
    //    ilen = 256;
      }
      return true;
    } 
    
    void W25Q32_Read(uint16_t page_number, uint8_t offset, uint8_t* pdataBuff , uint8_t len)
    {
      uint8_t wBuff[4]={0};
      uint8_t buf[255] ={0};
      
      uint32_t address =0;
      
      address = getFlashAddr(page_number, offset);
      
      Write_Disable(); 
      
      while ((W25Q32_BUSY() == BUSY));//&&(Write_Disable() == WRTEN));
      
      wBuff[0] = W25Q32_READ_DATA;
      wBuff[1] = (address >> 16)&0xff;
      wBuff[2] = (address >> 8)&0xff;
      wBuff[3] = (address)&0xff;
      
      spi_xfer_done = false;  
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), buf, sizeof(buf)));
      while (!spi_xfer_done)
      {
        __WFE();
      }
      
      memcpy(pdataBuff, &buf[4], len);
    } 
    
    void W25Q32_ReadOnlyReg(uint8_t cmd, uint8_t* dummyBytes, uint8_t len1, uint8_t* pdataBuff , uint8_t len2)
    {
      uint8_t wBuff[5];
      
      wBuff[0] = cmd;
      
      memcpy(&wBuff[1], dummyBytes, len1);
      
      spi_xfer_done = false;  
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, wBuff, sizeof(wBuff), pdataBuff,len2));
      while (!spi_xfer_done)
      {
        __WFE();
      }
    }
    /**
    * @brief SPI user event handler.
    * @param event
    */
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
      spi_xfer_done = true;
    }
    
    
    void spi_init(void)
    {
      nrf_drv_spi_config_t spi_config;// = NRF_DRV_SPI_DEFAULT_CONFIG;
      
      spi_config.ss_pin   = SPIM0_SS_PIN; //P0.5
      spi_config.miso_pin = SPIM0_MISO_PIN; //P0.6
      spi_config.mosi_pin = SPIM0_MOSI_PIN; //P0.3
      spi_config.sck_pin  = SPIM0_SCK_PIN;  //P0.4
      spi_config.frequency = NRF_DRV_SPI_FREQ_4M; //4 Mbps
      spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST; //Most significant bit shifted out first.
      spi_config.irq_priority = 2; // 7 :Interrupt priority.
      spi_config.mode = NRF_DRV_SPI_MODE_3; //SCK active low ((clk polarity)CPOL = 0), sample on trailing edge of clock ((clk phase)CPHA = 0).
      spi_config.orc = 0xFF; //Over-run character.       
    
      APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));  
    }
    
    
    void Write_Shot_Info(uint8_t *data, uint8_t len)
    {
      W25Q32_erase(0, 0, 256);
      W25Q32_writeBytes(0, 0, data, len);
    }
    
    void Read_Shot_Info(uint8_t *data, uint8_t len)
    {
      W25Q32_readBytes(0, 0, data, len);
    }
    
    void Write_Shot_Sample(void)
    {
    //  W25Q32_writeBytes(flash.write_page, 0, &sample_buffer[0][0], sizeof(sample_buffer));
      W25Q32_writeBytes(write_page, 0, &sample_buffer[0][0], sizeof(sample_buffer));
      nrf_delay_ms(3);
      //flash.write_page = flash.write_page + 20;
      write_page = write_page + 20;
    }
    
    void Read_Shot_Sample(void)
    {
      W25Q32_readBytes(read_page, 0, &sample_buffer[0][0], sizeof(sample_buffer));
    
    //  W25Q32_readBytes(flash.read_page, 0, &sample_buffer[0][0], sizeof(sample_buffer));
      //flash.read_page = flash.read_page + 20;
      read_page = read_page + 20;
    }
    
    :

  • What IRQ level are you calling the SPI functions from? Where does the code get stuck? Is it in a "while (!spi_xfer_done)"? Or is it an APP_ERROR_CHECK() that returns?

    Or does the code run fine, but it is only the transfer of data that is not working? Have you tried to analyse the MOSI pin, using a logic analyzer or an oscilloscope? 

    Would it be possible to send a stripped down version of the product that can reproduce the issue?

    BR,

    Edvin

Related