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











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