SPIM

52832支持3個SPI接口



注意地址是一樣的,中斷入口也是一樣的,所以一個ID只能使用其中一個功能。意味着,NRF52832只有3個同步串行通訊模塊。如:使用了0x40003000地址的SPI就不能再註冊0x40003000地址的SPIM、SPIS、TWIM、TWIS、TWI 。






1、註冊一個SPI


2、設置SPI速率(以前遇到操作外掛flash速率太快,讀出來的數據都是0xff)


3、SPI模式,CPOL、CPHA的搭配可以有四種工作模式,極性Polarity(CPOL規定無數據傳輸時CLK的電平、相位Phase(CPHA規定數據傳輸時採樣的時刻。
對於一個時鐘週期內,有兩個edge,分別稱爲:
Leading edge=前一個邊沿=第一個邊沿,對於開始電壓是1,那麼就是1變成0的時候,對於開始電壓是0,那麼就是0變成1的時候;

Trailing edge=後一個邊沿=第二個邊沿,對於開始電壓是1,那麼就是0變成1的時候(即在第一次1變成0之後,纔可能有後面的0變成1),對於開始電壓是0,那麼就是1變成0的時候;





4、高位先傳還是低位先傳





以W25Q32爲例分析


框1說明 對該flash寫操作是上升沿,讀操作是下降沿。

框2說明 該SPI FLASH工作模式有2種,模式0和模式3。


假設 是工作模式0:



MSB高位在前。



W25Q32控制程序:




1、註冊一個SPI,控制一個外設:

默認管腳參數修改 在 nrf_drv_config.h  ,這裏涉及到 SPI instance index ,SPI_INSTANCE=0/1/2



#define SPI_INSTANCE  0 /**< SPI instance index. */
nrf_drv_spi_t m_spi_master = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */

bool spi_xfer_done;

void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
{
    spi_xfer_done = true;
}

void SPI_Master_Init(void)
{

uint32_t err_code = NRF_SUCCESS;
nrf_drv_spi_config_t spi_config={
.sck_pin      = 2,
.mosi_pin     = 3,
.miso_pin     = 4,
.ss_pin       = 29,
.irq_priority = APP_IRQ_PRIORITY_HIGH,
.orc          = 0xFF,
.frequency    = NRF_DRV_SPI_FREQ_1M,
.mode         = NRF_DRV_SPI_MODE_0,
.bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
};
    err_code = nrf_drv_spi_init(&m_spi_master, &spi_config, spi_event_handler);
APP_ERROR_CHECK(err_code);
}

uint8_t r_tab[6]={0}; //此處注意 數組 r_tab 和 w_tab 的大小。
void SPI_Flash_ReadID(void)

uint32_t err_code;
uint8_t w_tab[4]={0x90,0x00,0x00,0x00};

spi_xfer_done = false;
err_code = nrf_drv_spi_transfer(&m_spi_master,w_tab,4,r_tab,6);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();//等到事件完成
}
}


通過按鍵事件觸發調用SPI_Flash_ReadID(); 調試模式下的值




2、註冊兩個SPI,控制兩個外設:(單獨信號線,單獨使能線)






3、註冊一個SPI,控制多個外設:(共用信號線,單獨使能線)

這種是通過片選來分別,分時複用,所以一般都將ss_pin禁用,在更高一層的設備驅動用軟件控制GPIO來實現。

void SPI_Master_Init_1(void)
{
nrf_gpio_cfg_output(SPI_FLASH_CS_1);//user define ss_pin
nrf_gpio_cfg_output(SPI_FLASH_CS_2);//user define ss_pin


uint32_t err_code = NRF_SUCCESS;
nrf_drv_spi_config_t spi_config={
.sck_pin      = 2,
.mosi_pin     = 3,
.miso_pin     = 4,
.ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,
.irq_priority = APP_IRQ_PRIORITY_HIGH,
.orc          = 0xFF,
.frequency    = NRF_DRV_SPI_FREQ_4M,
.mode         = NRF_DRV_SPI_MODE_0,
.bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
};
    err_code = nrf_drv_spi_init(&m_spi_master, &spi_config, spi_event_handler);
APP_ERROR_CHECK(err_code);
}


uint8_t r_tab_1[6]={0};
void SPI_Flash_ReadID_1(void)
{
uint32_t err_code;
uint8_t w_tab[4]={0x90,0x00,0x00,0x00};
memset(&r_tab_1, 0, sizeof(r_tab_1));
SPIFlash_Enable_CS_1;
spi_xfer_done = false;
err_code = nrf_drv_spi_transfer(&m_spi_master,w_tab,4,r_tab_1,6);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_1;
}


uint8_t r_tab_2[6]={0};
void SPI_Flash_ReadID_2(void)
{
uint32_t err_code;
uint8_t w_tab[4]={0x90,0x00,0x00,0x00};
memset(&r_tab_2, 0, sizeof(r_tab_2));
SPIFlash_Enable_CS_2;
spi_xfer_done = false;
err_code = nrf_drv_spi_transfer(&m_spi_master,w_tab,4,r_tab_2,6);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_2;
}


通過按鍵事件觸發調用SPI_Flash_ReadID_1(); 和SPI_Flash_ReadID_2(); 調試模式下的值。問號應該是沒關另一個片選。




3、讀、寫、擦除操作

void SPI_Flash_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead)
{
uint32_t err_code; 
uint16_t i;
uint8_t SPI_CMD[4] = {0};
uint8_t uBuffer[NumByteToRead+4];
SPI_CMD[0] = W25X_ReadData;
SPI_CMD[1] = (uint8_t)((ReadAddr)>>16);
SPI_CMD[2] = (uint8_t)((ReadAddr)>>8);
SPI_CMD[3] = (uint8_t)ReadAddr;
spi_xfer_done = false;
SPIFlash_Enable_CS_1;//if use system ss_pin ,cancel this
SPIFlash_Disable_CS_2;//if use system ss_pin ,cancel this

err_code = nrf_drv_spi_transfer(&m_spi_master,SPI_CMD,4,uBuffer,NumByteToRead+4);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
for(i=0;i<NumByteToRead;i++)//remove the invalid date
{
pBuffer[i] = uBuffer[i+4];
}
  SPIFlash_Disable_CS_1;//if use system ss_pin ,cancel this
}


uint8_t SpiFlash_ReadSR(void)
{
uint32_t err_code; 
uint8_t SPI_CMD[1] = {0};
uint8_t SPI_GET[2] = {0,0};
SPI_CMD[0] = W25X_ReadStatusReg;
spi_xfer_done = false;
  SPIFlash_Enable_CS_1;//if use system ss_pin ,cancel this
SPIFlash_Disable_CS_2;//if use system ss_pin ,cancel this
err_code = nrf_drv_spi_transfer(&m_spi_master,SPI_CMD,1,SPI_GET,2);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_1;//if use system ss_pin ,cancel this
return SPI_GET[1];
}

void SPI_Flash_Wait_Busy(void)
{
while ((SpiFlash_ReadSR()&0x01)==0x01);
}

void SPI_FLASH_Write_Enable(void)
{
uint32_t err_code;
uint8_t SPI_CMD[1] = {0};
SPI_CMD[0] = W25X_WriteEnable;
spi_xfer_done = false;
SPIFlash_Enable_CS_1;//if use system ss_pin ,cancel this
SPIFlash_Disable_CS_2;//if use system ss_pin ,cancel this
err_code = nrf_drv_spi_transfer(&m_spi_master,SPI_CMD,1,NULL,NULL);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_1;//if use system ss_pin ,cancel this
}

void SPI_Flash_Write_Page(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite)
{
uint32_t err_code;
uint16_t i;
uint8_t SPI_CMD[4+NumByteToWrite];
SPI_CMD[0] = W25X_PageProgram;
SPI_CMD[1] = (uint8_t)((WriteAddr)>>16);
SPI_CMD[2] = (uint8_t)((WriteAddr)>>8);
SPI_CMD[3] = (uint8_t)WriteAddr;
for(i=0;i<NumByteToWrite;i++)
{
SPI_CMD[i+4] = pBuffer[i];
}
  SPI_FLASH_Write_Enable(); 
spi_xfer_done = false;
  SPIFlash_Enable_CS_1;//if use system ss_pin ,cancel this
SPIFlash_Disable_CS_2;//if use system ss_pin ,cancel this
err_code = nrf_drv_spi_transfer(&m_spi_master,SPI_CMD,4+NumByteToWrite,NULL,NULL);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_1;//if use system ss_pin ,cancel this
SPI_Flash_Wait_Busy(); 
}

void SPI_Flash_Erase_Sector(uint32_t Dst_Addr)
{
uint32_t err_code; 
Dst_Addr*=4096;
uint8_t SPI_CMD[4];
SPI_CMD[0] = W25X_SectorErase;
SPI_CMD[1] = (uint8_t)((Dst_Addr)>>16);
SPI_CMD[2] = (uint8_t)((Dst_Addr)>>8);
SPI_CMD[3] = (uint8_t)Dst_Addr;
SPI_FLASH_Write_Enable(); 
SPI_Flash_Wait_Busy(); 

spi_xfer_done = false;
  SPIFlash_Enable_CS_1;//if use system ss_pin ,cancel this
SPIFlash_Disable_CS_2;//if use system ss_pin ,cancel this
err_code = nrf_drv_spi_transfer(&m_spi_master,SPI_CMD,4,NULL,NULL);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_1;//if use system ss_pin ,cancel this
SPI_Flash_Wait_Busy();  
}

void SPI_Flash_Erase_Chip(void)   
{    
uint32_t err_code; 
uint8_t SPI_CMD[1];
SPI_CMD[0] = W25X_ChipErase;
SPI_FLASH_Write_Enable(); 
SPI_Flash_Wait_Busy(); 

spi_xfer_done = false;
  SPIFlash_Enable_CS_1;//if use system ss_pin ,cancel this
SPIFlash_Disable_CS_2;//if use system ss_pin ,cancel this
err_code = nrf_drv_spi_transfer(&m_spi_master,SPI_CMD,1,NULL,NULL);
APP_ERROR_CHECK(err_code);
while(!spi_xfer_done)
{
__WFE();
}
SPIFlash_Disable_CS_1;//if use system ss_pin ,cancel this
SPI_Flash_Wait_Busy(); 
}




調試遇到問題:

1、在初始化的地方操作W25Q32是沒問題的,當移到定時器或按鍵事件中操作,就會一直卡在 __WFE(); 。

解決辦法:把APP_IRQ_PRIORITY_LOW  改爲 APP_IRQ_PRIORITY_HIGH ,需要添加超時處理??


2、外掛兩個W25Q32,操作一個是要把另外一個disable,否則會出現一些意想不到的錯誤數據。











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章