52832支持3個SPI接口
注意地址是一樣的,中斷入口也是一樣的,所以一個ID只能使用其中一個功能。意味着,NRF52832只有3個同步串行通訊模塊。如:使用了0x40003000地址的SPI就不能再註冊0x40003000地址的SPIM、SPIS、TWIM、TWIS、TWI 。
1、註冊一個SPI
2、設置SPI速率(以前遇到操作外掛flash速率太快,讀出來的數據都是0xff)
對於一個時鐘週期內,有兩個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,否則會出現一些意想不到的錯誤數據。