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,否则会出现一些意想不到的错误数据。