打印
[开发板]

【CW32L031CxTx StartKit评估板测评】6.SPI的使用

[复制链接]
472|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创# @21小跑堂  

串行外设接口(SPI)是一种同步串行数据通信接口,常用于 MCU 与外部设备之间进行同步串行通信,CW32L031 内部集成 1 个串行外设 SPI 接口,在开发板上SPI接了一颗W25Q64的FLASH

开发板上实际焊接的是芯源自家的CW25Q64,在https://www.whxy.com/support/filelist/23这里能下载到手册
先来尝试用SPI读取FLAH的ID并用串口打印出来,初始化SPI接口
void spi_init()
{
    SPI_InitTypeDef  SPI_InitStructure = {0};
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    __RCC_GPIOA_CLK_ENABLE();
    __RCC_SPI1_CLK_ENABLE();
   
    PA10_AFx_SPI1SCK();
    PA11_AFx_SPI1MISO();
    PA12_AFx_SPI1MOSI();
    PA15_AFx_SPI1CS();
   
    GPIO_InitStructure.Pins = GPIO_PIN_10|GPIO_PIN_12|GPIO_PIN_15;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
   
    GPIO_InitStructure.Pins = GPIO_PIN_11;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_Init(CW_GPIOA, &GPIO_InitStructure);
   
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;    // 双线全双工
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;                         // 主机模式
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;                     // 帧数据长度为8bit
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;                           // 时钟空闲电平为高
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;                          // 第二个边沿采样
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;                             // 片选信号由SSI寄存器控制
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;    // 波特率为PCLK的8分频
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;                    // 最高有效位 MSB 收发在前
    SPI_InitStructure.SPI_Speed = SPI_Speed_High;                         // 高速SPI

    SPI_Init(CW_SPI1, &SPI_InitStructure);
    SPI_Cmd(CW_SPI1, ENABLE);
   
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
}
读Flash id,需要注意的是在全双工模式下读之前要先发送,不然无法接受从设备发过来的数据

uint8_t spi_sendbyte(SPI_TypeDef* SPIx,uint8_t data)
{
    while(SPI_GetFlagStatus(SPIx, SPI_FLAG_TXE) == RESET);
    SPI_SendData(SPIx,data);
    while(SPI_GetFlagStatus(SPIx, SPI_FLAG_RXNE) == RESET);
    return SPI_ReceiveData(SPIx)&0xFF;
}

uint8_t spi_readbyte(SPI_TypeDef* SPIx)
{
    return spi_sendbyte(SPIx,0x00);
}

void cw25q64_readflashid()
{
    uint8_t data[8] = {0},i=0;
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x90);
    spi_sendbyte(CW_SPI1,0x00);
    spi_sendbyte(CW_SPI1,0x00);
    spi_sendbyte(CW_SPI1,0x00);
    data[0] = spi_readbyte(CW_SPI1);
    data[1] = spi_readbyte(CW_SPI1);
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash read Manufacturer/Device ID %02X %02X\n",data[0],data[1]);
   
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x9F);
    data[0] = spi_readbyte(CW_SPI1);
    data[1] = spi_readbyte(CW_SPI1);
    data[2] = spi_readbyte(CW_SPI1);
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash read JEDEC ID %02X %02X%02X\n",data[0],data[1],data[2]);
   
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x5A);
    spi_sendbyte(CW_SPI1,0x00);
    spi_sendbyte(CW_SPI1,0x00);
    spi_sendbyte(CW_SPI1,0xF8);
    spi_sendbyte(CW_SPI1,0x00);
    while(i<8)
    {
        data[i] = spi_readbyte(CW_SPI1);
        i++;
    }
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash read Unique Id %02X%02X%02X%02X%02X%02X%02X%02X\n",data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]);
}
运行结果

Device ID的ID7 - ID0这个值实际读到的和手册不一致

Unique Id是01开头F6结尾

接下来尝试写入数据,先要使能写入,然后擦除,等待擦除完成后写入数据
void cw25q64_waitwritefinish()
{
    uint8_t writebusy = 1;
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x05);
    while(writebusy != 0)
    {
        writebusy = spi_readbyte(CW_SPI1)&0x01;
    }
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash write finish\n");
}

void cw25q64_writeenable()
{
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x06);
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash write enabled\n");
}

void cw25q64_erasesector(uint32_t secteraddr)
{
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x20);
    spi_sendbyte(CW_SPI1,(secteraddr >> 16)&0xFF);
    spi_sendbyte(CW_SPI1,(secteraddr >> 8)&0xFF);
    spi_sendbyte(CW_SPI1,secteraddr&0xFF);
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash erase sector %08X\n",secteraddr);
}

void cw25q64_writepagedata(uint32_t pageaddr,uint8_t *datas,uint16_t len)
{
    uint16_t index = 0;
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x02);
    spi_sendbyte(CW_SPI1,(pageaddr >> 16)&0xFF);
    spi_sendbyte(CW_SPI1,(pageaddr >> 8)&0xFF);
    spi_sendbyte(CW_SPI1,pageaddr&0xFF);
    while(index < len)
    {
        spi_sendbyte(CW_SPI1,datas[index]);
        index += 1;
    }
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash write page %08X data:\n",pageaddr);
    index = 0;
    while(index < len)
    {
        printf("%02X ",datas[index]);
        index += 1;
    }
    printf("\n");
}

void cw25q64_readdata(uint32_t addr,uint8_t *datas,uint16_t len)
{
    uint16_t index = 0;
    SPI_NSSInternalSoftwareConfig(CW_SPI1,0);
    spi_sendbyte(CW_SPI1,0x03);
    spi_sendbyte(CW_SPI1,(addr >> 16)&0xFF);
    spi_sendbyte(CW_SPI1,(addr >> 8)&0xFF);
    spi_sendbyte(CW_SPI1,addr&0xFF);
    while(index < len)
    {
        datas[index] = spi_readbyte(CW_SPI1)&0xFF;
        index += 1;
    }
    SPI_NSSInternalSoftwareConfig(CW_SPI1,1);
    printf("Flash read %08X data:\n",addr);
    index = 0;
    while(index < len)
    {
        printf("%02X ",datas[index]);
        index += 1;
    }
    printf("\n");
}
int32_t main(void)
{
    uint8_t flash_testdata[50] = {0},index = 0;
    RCC_HSI_48M_init();
    RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
    RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
    uart1_init();
    spi_init();
    cw25q64_readflashid();
    while(index < 50)
    {
        index += 1;
        flash_testdata[index] = index;
    }
    cw25q64_writeenable();
    cw25q64_erasesector(0);
    cw25q64_waitwritefinish();
    cw25q64_writeenable();
    cw25q64_writepagedata(0,flash_testdata,50);
    cw25q64_waitwritefinish();
    cw25q64_readdata(0,flash_testdata,50);
    while (1)
    {
    }
}
运行结果

除了读写FLASH,这块LCD12864的屏幕也可以用SPI驱动

驱动它要用到5个IO,CS RST A0 MOSI SCK,SPI只用发送模式就可以了MISO可以不用,这里换一组IO
YUYY_HS12864G18B_DEV_t hs12864_dev;
void hs12864g18b_init(void)
{
    GPIO_InitTypeDef gpiodef;
    hs12864_dev.cs.gpio = CW_GPIOA;
    hs12864_dev.cs.pin = GPIO_PIN_4;
    hs12864_dev.rst.gpio = CW_GPIOA;
    hs12864_dev.rst.pin = GPIO_PIN_3;
    hs12864_dev.a0.gpio = CW_GPIOA;
    hs12864_dev.a0.pin = GPIO_PIN_2;
    hs12864_dev.sck.gpio = CW_GPIOA;
    hs12864_dev.sck.pin = GPIO_PIN_5;
    hs12864_dev.mo.gpio = CW_GPIOA;
    hs12864_dev.mo.pin = GPIO_PIN_7;
   
    __RCC_GPIOA_CLK_ENABLE();
    gpiodef.Pins = GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_4|GPIO_PIN_3|GPIO_PIN_2;
    gpiodef.Mode = GPIO_MODE_OUTPUT_PP;
    gpiodef.IT = GPIO_IT_NONE;
    GPIO_Init(CW_GPIOA,&gpiodef);
   
        #if(YUYY_HS12864G18B_USE_SOFT_SPI)
    yuyy_hs12864g18b_set_spigpio(NULL,&hs12864g18b_gpio_config);
    #else
    __RCC_SPI1_CLK_ENABLE();;
    PA05_AFx_SPI1SCK();
    PA07_AFx_SPI1MOSI();
    SPI_InitTypeDef spidef;
    spidef.SPI_Direction = SPI_Direction_1Line_TxOnly;
    spidef.SPI_Mode = SPI_Mode_Master;
    spidef.SPI_DataSize = SPI_DataSize_8b;
    spidef.SPI_CPOL = SPI_CPOL_High;
    spidef.SPI_CPHA = SPI_CPHA_2Edge;
    spidef.SPI_NSS = SPI_NSS_Soft;
    spidef.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    spidef.SPI_FirstBit = SPI_FirstBit_MSB;
    spidef.SPI_Speed = SPI_Speed_High;
    SPI_Init(CW_SPI1,&spidef);
    SPI_Cmd(CW_SPI1, ENABLE);
    hs12864_dev.spix = CW_SPI1;
    #endif
    yuyy_hs12864g18b_init(&hs12864_dev);
}

int32_t main(void)
{
    RCC_HSI_48M_init();
    RCC_HCLKPRS_Config(RCC_HCLK_DIV1);
    RCC_PCLKPRS_Config(RCC_PCLK_DIV1);
    hs12864g18b_init();
    yuyy_hs12864g18b_clear_screen(&hs12864_dev);
    yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,0,0,(uint8_t *)"CW32L031TEST");
    yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,2,0,(uint8_t *)"Drivered by SPI");
    yuyy_hs12864g18b_display_string_8x16(&hs12864_dev,0,4,0,(uint8_t *)"Code by yuyy1989");
    while (1)
    {
    }
}
运行效果

另外SPI还能用来驱动WS2812或SK6812这样的幻彩灯珠,这里就先不演示了



使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

145

主题

695

帖子

6

粉丝