123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- #include "SN_SPI.h"
- /*
- 文件名:SN_SPI.c/.h
- 作者: SN_FAE_黄泽洪
- 免责声明:无版权,可随意传播和篡改,该代码仅供开发参考,如需使用请自行验证
- 本人不担负商业使用上带来的风险。
- */
- /*
- SN_SPI模块使用方法
- 1.使用硬件nss
- uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88};
- uint8_t RX_BULL[8] = {0};
- int main(void){
-
- SN_SYSCLK_set(SYSCLK_48MHZ);
- std_delay_init();
- SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_PA6 );
- SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB );
-
- while(1){
- std_delayms(500);
- SN_SPI_TX_RX(BULL ,RX_BULL ,8);
- }
-
-
- }
-
-
- 2.使用软件设置普通io做CS片选
- uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88};
- uint8_t RX_BULL[8] = {0};
-
- int main(void){
-
- SN_SYSCLK_set(SYSCLK_48MHZ);
- std_delay_init();
- SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_NULL );
- SN_SPI_IO_SOF_cs(SPI_SOF_CS_PC1);
- SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB );
-
- while(1){
- std_delayms(500);
- SN_SPI_TX_RX(BULL ,RX_BULL ,8);
- }
- }
-
-
- 3.不使用片选,用户将spi从机强制设置CS下拉
- uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88};
- uint8_t RX_BULL[8] = {0};
-
- int main(void){
-
- SN_SYSCLK_set(SYSCLK_48MHZ);
- std_delay_init();
- SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_NULL );
- SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB );
-
- while(1){
-
- std_delayms(500);
- SN_SPI_TX_RX(BULL ,RX_BULL ,8);
-
- }
- }
- */
- //全局NSS引脚设置标志
- uint8_t SPI_NSS_EN = 0;
- GPIO_t * G_GPIO_X = NULL;
- uint16_t G_GPIO_PIN_x = 0;
- //全局唯一软件cs接口
- static struct
- {
- void (*SN_SPI_CS_H)(void) ; //用户实现这两个函数,并通过SN_SPI_CS_t,传入通信接收和发送函数中使用
- void (*SN_SPI_CS_L)(void) ;
-
- } SN_SPI_CS_t;
- //脱裤子放屁函数
- static void SN_SPI_SOF_CS_H(void){
- std_gpio_set_pin(G_GPIO_X, G_GPIO_PIN_x);
- }
- static void SN_SPI_SOF_CS_L(void){
- std_gpio_reset_pin(G_GPIO_X, G_GPIO_PIN_x);
- }
- /*
- 函数:void SN_SPI_IO_SOF_cs()
- 参数:软件cs片选引脚设置 (注意不要io冲突)
- @SPI_SOF_CS_PA0
- @SPI_SOF_CS_PA1
- @SPI_SOF_CS_PA2 //注意使用PA2是仿真接口,在线仿真时该io口不能被使用
- @SPI_SOF_CS_PA3
- @SPI_SOF_CS_PA4
- @SPI_SOF_CS_PA5
- @SPI_SOF_CS_PA7
- @SPI_SOF_CS_PB0
- @SPI_SOF_CS_PB1
- @SPI_SOF_CS_PB2
- @SPI_SOF_CS_PB3
- @SPI_SOF_CS_PB4
- @SPI_SOF_CS_PB5
- @SPI_SOF_CS_PB6 //注意使用PB6是仿真接口,在线仿真时该io口不能被使用
- @SPI_SOF_CS_PB7
- @SPI_SOF_CS_PC0
- @SPI_SOF_CS_PC1
- 返回:无
- */
- void SN_SPI_IO_SOF_cs(uint8_t SPI_SOF_CS_Px){
-
- std_gpio_init_t gpio_config = {0};
-
- uint32_t RCC_PERIPH_CLK_GPIOx = 0;
- RCC_PERIPH_CLK_GPIOx = (SPI_SOF_CS_Px < 9 ) ? RCC_PERIPH_CLK_GPIOA : ( SPI_SOF_CS_Px < 17) ? RCC_PERIPH_CLK_GPIOB : RCC_PERIPH_CLK_GPIOC; //时钟
- G_GPIO_X = (SPI_SOF_CS_Px < 9 ) ? GPIOA : ( SPI_SOF_CS_Px < 17) ? GPIOB : GPIOC; //端口
- G_GPIO_PIN_x = (SPI_SOF_CS_Px < 9 ) ? (GPIO_PIN_0<< (SPI_SOF_CS_Px - 1)): ( SPI_SOF_CS_Px < 17) ? (GPIO_PIN_0<< (SPI_SOF_CS_Px - 9)) : (GPIO_PIN_0<< (SPI_SOF_CS_Px - 17)); //引脚
-
- //初始化
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
- gpio_config.pin = G_GPIO_PIN_x; //选择IO编号
- gpio_config.mode = GPIO_MODE_OUTPUT; //设置为输出
- gpio_config.pull = GPIO_NOPULL; //无上下拉设置
- gpio_config.output_type = GPIO_OUTPUT_PUSHPULL; //推挽输出
- std_gpio_init(G_GPIO_X, &gpio_config); //初始
- //设置输出高
- std_gpio_set_pin(G_GPIO_X, G_GPIO_PIN_x); //设置cs为高,取消片选
-
- SN_SPI_CS_t.SN_SPI_CS_H = SN_SPI_SOF_CS_H ; //连接软件片选信号
- SN_SPI_CS_t.SN_SPI_CS_L = SN_SPI_SOF_CS_L ;
-
- }
- /*
- 函数:void SN_SPI_IO_set(uint8_t SPI_MOSI_x , uint8_t SPI_MISO_x , uint8_t SPI_SCK_x, uint8_t SPI_NSS_x)
- 参数:MOSI
- @SPI_MOSI_PA0
- @SPI_MOSI_PA7
- @SPI_MOSI_PB7
- 参数:MISO
- @SPI_MISO_PA1
- @SPI_MISO_PB6 (PB6是仿真接口,在线仿真时不要用)
- @SPI_MISO_PC1
- 参数:SCK
- @SPI_SCK_PA6
- @SPI_SCK_PB0
- @SPI_SCK_PB2
- 参数:NSS
- @SPI_NSS_NULL (不使用硬件片选,用户要自行设置软件cs使能调用)
- @SPI_NSS_PA6
- @SPI_NSS_PB0
- @SPI_NSS_PB2
-
- 返回:无
- */
- void SN_SPI_IO_set(uint8_t SPI_MOSI_x , uint8_t SPI_MISO_x , uint8_t SPI_SCK_x, uint8_t SPI_NSS_x ){
- //注意 spi初始化的 sck 电平
- std_gpio_init_t gpio_config = {0};
-
- uint32_t RCC_PERIPH_CLK_GPIOx = 0;
- GPIO_t * GPIO_X = NULL;
- uint16_t GPIO_PIN_x = 0;
- uint8_t GPIO_AF0_x = 0;
-
- //处理SPI_MOSI
- GPIO_AF0_x = GPIO_AF0_SPI1; //af复用选项
- GPIO_PIN_x = (SPI_MOSI_x == 1) ? GPIO_PIN_0 : GPIO_PIN_7 ; //设置引脚io
- GPIO_X = (SPI_MOSI_x != 3) ? GPIOA : GPIOB ; //设置io端口
- RCC_PERIPH_CLK_GPIOx = ( SPI_MOSI_x != 3) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB ; //设置时钟
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
- gpio_config.pin = GPIO_PIN_x; //选择IO编号
- gpio_config.mode = GPIO_MODE_ALTERNATE; //设置为复用功能
- gpio_config.pull = GPIO_NOPULL; //无上下拉设置
- gpio_config.output_type = GPIO_OUTPUT_PUSHPULL; //推挽输出
- gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
- std_gpio_init(GPIO_X, &gpio_config); //初始
- //处理SPI_MISO
- GPIO_AF0_x = ( SPI_MISO_x != 2 ) ? GPIO_AF0_SPI1 : GPIO_AF4_SPI1 ; //af复用选项
- GPIO_PIN_x = ( SPI_MISO_x == 1 ) ? GPIO_PIN_1 : (( SPI_MISO_x == 2 ) ? ( GPIO_PIN_6 ): (GPIO_PIN_1 )) ; //设置引脚io
- GPIO_X = ( SPI_MISO_x == 1 ) ? GPIOA : (( SPI_MISO_x == 2 ) ? ( GPIOB ): ( GPIOC )) ; //设置io端口
- RCC_PERIPH_CLK_GPIOx = ( SPI_MISO_x == 1 ) ? RCC_PERIPH_CLK_GPIOA : (( SPI_MISO_x == 2 ) ? ( RCC_PERIPH_CLK_GPIOB): ( RCC_PERIPH_CLK_GPIOC )) ; //设置时钟
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
-
- gpio_config.pin = GPIO_PIN_x ; //选择IO编号
- gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
- std_gpio_init(GPIO_X, &gpio_config); //初始
-
- //SPI_SCK
- GPIO_AF0_x = ( SPI_SCK_x == 1 ) ? GPIO_AF4_SPI1 : GPIO_AF0_SPI1 ; //af复用选项
- GPIO_PIN_x = ( SPI_SCK_x == 1 ) ? GPIO_PIN_6 : (( SPI_SCK_x == 2 ) ? ( GPIO_PIN_0 ): (GPIO_PIN_2 )) ; //设置引脚io
- GPIO_X = ( SPI_SCK_x == 1 ) ? GPIOA : GPIOB ; //设置io端口
- RCC_PERIPH_CLK_GPIOx = ( SPI_SCK_x == 1 ) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB; //设置时钟
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
- gpio_config.pull = GPIO_PULLUP;
- gpio_config.pin = GPIO_PIN_x ; //选择IO编号
- gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
- std_gpio_init(GPIO_X, &gpio_config); //初始
-
- //SPI_NSS
- if(SPI_NSS_x != 1){
-
- GPIO_AF0_x = GPIO_AF0_SPI1; //af复用选项
- GPIO_PIN_x = ( SPI_NSS_x == 2 ) ? GPIO_PIN_6 : ( SPI_NSS_x == 3 ) ? GPIO_PIN_1 : GPIO_PIN_5 ; //设置引脚io
- GPIO_X = ( SPI_NSS_x == 2 ) ? GPIOA : GPIOB ; //设置io端口
- RCC_PERIPH_CLK_GPIOx = ( SPI_NSS_x == 2 ) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB; //设置时钟
- std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
- gpio_config.pin = GPIO_PIN_x ; //选择IO编号
- gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
- std_gpio_init(GPIO_X, &gpio_config); //初始
-
-
- }else{
-
- SPI_NSS_EN = 1; //设置全局标志,说明NSS引脚没被使用
-
- }
- }
- /*
- 函数:SN_SPI_MASTER_init(uint32_t SPI_DIV, uint8_t SPI_MODE_X , uint8_t SPI_MSB_OR_LSB )
- 参数:spi分频系数(分频系数)
- @SPI_BAUD_PCLKDIV_2 SPI速率为fPLCK/2 最高24M,系统时钟必须在48MHZ
- @SPI_BAUD_PCLKDIV_4 SPI速率为fPLCK/4
- @SPI_BAUD_PCLKDIV_8 SPI速率为fPLCK/8
- @SPI_BAUD_PCLKDIV_16 SPI速率为fPLCK/16
- @SPI_BAUD_PCLKDIV_32 SPI速率为fPLCK/32
- @SPI_BAUD_PCLKDIV_64 SPI速率为fPLCK/64
- @SPI_BAUD_PCLKDIV_128 SPI速率为fPLCK/128
- 参数:spi通信模式
- @SPI_MODE_0
- @SPI_MODE_1
- @SPI_MODE_2
- @SPI_MODE_3
- 参数:spi数据对齐选择
- @SPI_MSB
- @SPI_LSB
-
- 返回:无
- */
- void SN_SPI_MASTER_init(uint32_t SPI_DIV, uint8_t SPI_MODE_X , uint8_t SPI_MSB_OR_LSB ){
-
- uint32_t SPI_POLARIT_x = 0;
- uint32_t SPI_PHASE_x = 0;
-
- //处理spi模块
- std_spi_init_t spi_config = {0};
-
- /* SPI1时钟使能 */
- std_rcc_apb2_clk_enable(RCC_PERIPH_CLK_SPI1);
-
- /* 禁止SPI */
- std_spi_disable();
-
- /* SPI结构体初始化 使用SPI的00模式 */
- spi_config.mode = SPI_MODE_MASTER;
- spi_config.baud_rate_prescaler = SPI_DIV; //spi工作速率
- //设置spi模式
- SPI_POLARIT_x = ((SPI_MODE_X == 0) || (SPI_MODE_X == 1)) ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH ;
- SPI_PHASE_x = ((SPI_MODE_X == 0) || (SPI_MODE_X == 2)) ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE ;
-
-
- spi_config.clk_polarity = SPI_POLARIT_x; //时钟空闲下为高电平
- spi_config.clk_phase = SPI_PHASE_x; //第一个时钟边沿采样
-
- spi_config.bitorder = SPI_MSB_OR_LSB; //先发高位
- std_spi_init(&spi_config); //初始化参数
-
- /* SPI主机模式,配置NSS输出使能 */
- if(SPI_NSS_EN == 0 ){
- std_spi_nss_output_enable();
- SN_SPI_CS_t.SN_SPI_CS_H = NULL;
- SN_SPI_CS_t.SN_SPI_CS_L = NULL;
- }
-
- /* SPI使能 */
- std_spi_enable(); //使能SPI
- }
- /*
- 函数:SN_SPI_TX_RX(uint8_t * send_data ,uint8_t * read_data ,uint16_t len)
- 功能:通过spi发送数据
- 参数:发送数组
- 参数:数组长度
- 返回: 无
- */
- void SN_SPI_TX_RX(uint8_t * send_data ,uint8_t * read_data ,uint16_t len){
-
- uint16_t index = 0;
-
- /* SPI主机模式,拉低片选信号 */
- if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); }
- std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW);
- /* SPI数据传输 */
- for(index=0; index<len; index++)
- {
- /* 等待发送数据寄存器为空 */
- while(std_spi_get_flag(SPI_FLAG_TXFE) != SPI_FLAG_TXFE);
- /* 发送数据 */
- std_spi_write_data(send_data[index]);
-
- /* 等待接收数据寄存器非空 */
- while(std_spi_get_flag(SPI_FLAG_RXFNE) != SPI_FLAG_RXFNE);
- /* 接收数据 */
- read_data[index] = std_spi_read_data();
- }
-
- /* SPI主机拉高片选信号,结束通信 */
- while(!std_spi_get_flag(SPI_FLAG_TXFE));
- while(std_spi_get_flag(SPI_FLAG_BUSY));
-
-
-
- /* SPI主机模式,拉高片选信号 */
- if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_H(); }
- std_spi_set_nss_output(SPI_NSS_OUTPUT_HIGH);
-
- }
- /*
- 函数:SN_SPI_TX(uint8_t * send_data ,uint16_t len)
- 功能:通过spi发送数据
- 参数:发送数组
- 参数:数组长度
- 返回: 无
- */
- void SN_SPI_TX(uint8_t * send_data ,uint16_t len){
- uint16_t index = 0;
-
- /* SPI主机模式,拉低片选信号 */
- if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); }
- std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW);
- /* SPI数据传输 */
- for(index=0; index<len; index++)
- {
- /* 等待发送数据寄存器为空 */
- while(std_spi_get_flag(SPI_FLAG_TXFE) != SPI_FLAG_TXFE);
- /* 发送数据 */
- std_spi_write_data(send_data[index]);
-
- /* 等待接收数据寄存器非空 */
- while(std_spi_get_flag(SPI_FLAG_RXFNE) != SPI_FLAG_RXFNE);
- /* 接收数据 */
- std_spi_read_data(); //丢弃接收数据
- }
-
- /* SPI主机拉高片选信号,结束通信 */
- while(!std_spi_get_flag(SPI_FLAG_TXFE));
- while(std_spi_get_flag(SPI_FLAG_BUSY));
-
-
-
- /* SPI主机模式,拉高片选信号 */
- if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_H(); }
- std_spi_set_nss_output(SPI_NSS_OUTPUT_HIGH);
- }
- /*
- 函数:SN_SPI_RX(uint8_t * read_data ,uint16_t len)
- 功能:通过spi接收数据
- 参数:发送数组
- 参数:数组长度
- 返回: 无
- */
- void SN_SPI_RX(uint8_t * read_data ,uint16_t len){
- uint16_t index = 0;
-
- /* SPI主机模式,拉低片选信号 */
- if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); }
- std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW);
- /* SPI数据传输 */
- for(index=0; index<len; index++)
- {
- /* 等待发送数据寄存器为空 */
- while(std_spi_get_flag(SPI_FLAG_TXFE) != SPI_FLAG_TXFE);
- /* 发送数据 */
- std_spi_write_data(0x00); //推空数据出去
-
- /* 等待接收数据寄存器非空 */
- while(std_spi_get_flag(SPI_FLAG_RXFNE) != SPI_FLAG_RXFNE);
- /* 接收数据 */
- read_data[index] = std_spi_read_data();
- }
-
- /* SPI主机拉高片选信号,结束通信 */
- while(!std_spi_get_flag(SPI_FLAG_TXFE));
- while(std_spi_get_flag(SPI_FLAG_BUSY));
-
-
-
- /* SPI主机模式,拉高片选信号 */
- if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_H(); }
- std_spi_set_nss_output(SPI_NSS_OUTPUT_HIGH);
- }
|