SN_SPI.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. #include "SN_SPI.h"
  2. /*
  3. 文件名:SN_SPI.c/.h
  4. 作者: SN_FAE_黄泽洪
  5. 免责声明:无版权,可随意传播和篡改,该代码仅供开发参考,如需使用请自行验证
  6. 本人不担负商业使用上带来的风险。
  7. */
  8. /*
  9. SN_SPI模块使用方法
  10. 1.使用硬件nss
  11. uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88};
  12. uint8_t RX_BULL[8] = {0};
  13. int main(void){
  14. SN_SYSCLK_set(SYSCLK_48MHZ);
  15. std_delay_init();
  16. SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_PA6 );
  17. SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB );
  18. while(1){
  19. std_delayms(500);
  20. SN_SPI_TX_RX(BULL ,RX_BULL ,8);
  21. }
  22. }
  23. 2.使用软件设置普通io做CS片选
  24. uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88};
  25. uint8_t RX_BULL[8] = {0};
  26. int main(void){
  27. SN_SYSCLK_set(SYSCLK_48MHZ);
  28. std_delay_init();
  29. SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_NULL );
  30. SN_SPI_IO_SOF_cs(SPI_SOF_CS_PC1);
  31. SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB );
  32. while(1){
  33. std_delayms(500);
  34. SN_SPI_TX_RX(BULL ,RX_BULL ,8);
  35. }
  36. }
  37. 3.不使用片选,用户将spi从机强制设置CS下拉
  38. uint8_t BULL[8] = {0X11,0X22,0X33,0X44,0X55,0X66,0X77,0X88};
  39. uint8_t RX_BULL[8] = {0};
  40. int main(void){
  41. SN_SYSCLK_set(SYSCLK_48MHZ);
  42. std_delay_init();
  43. SN_SPI_IO_set(SPI_MOSI_PB7 , SPI_MISO_PC1 , SPI_SCK_PB2, SPI_NSS_NULL );
  44. SN_SPI_MASTER_init(SPI_BAUD_PCLKDIV_128, SPI_MODE_2 , SPI_MSB );
  45. while(1){
  46. std_delayms(500);
  47. SN_SPI_TX_RX(BULL ,RX_BULL ,8);
  48. }
  49. }
  50. */
  51. //全局NSS引脚设置标志
  52. uint8_t SPI_NSS_EN = 0;
  53. GPIO_t * G_GPIO_X = NULL;
  54. uint16_t G_GPIO_PIN_x = 0;
  55. //全局唯一软件cs接口
  56. static struct
  57. {
  58. void (*SN_SPI_CS_H)(void) ; //用户实现这两个函数,并通过SN_SPI_CS_t,传入通信接收和发送函数中使用
  59. void (*SN_SPI_CS_L)(void) ;
  60. } SN_SPI_CS_t;
  61. //脱裤子放屁函数
  62. static void SN_SPI_SOF_CS_H(void){
  63. std_gpio_set_pin(G_GPIO_X, G_GPIO_PIN_x);
  64. }
  65. static void SN_SPI_SOF_CS_L(void){
  66. std_gpio_reset_pin(G_GPIO_X, G_GPIO_PIN_x);
  67. }
  68. /*
  69. 函数:void SN_SPI_IO_SOF_cs()
  70. 参数:软件cs片选引脚设置 (注意不要io冲突)
  71. @SPI_SOF_CS_PA0
  72. @SPI_SOF_CS_PA1
  73. @SPI_SOF_CS_PA2 //注意使用PA2是仿真接口,在线仿真时该io口不能被使用
  74. @SPI_SOF_CS_PA3
  75. @SPI_SOF_CS_PA4
  76. @SPI_SOF_CS_PA5
  77. @SPI_SOF_CS_PA7
  78. @SPI_SOF_CS_PB0
  79. @SPI_SOF_CS_PB1
  80. @SPI_SOF_CS_PB2
  81. @SPI_SOF_CS_PB3
  82. @SPI_SOF_CS_PB4
  83. @SPI_SOF_CS_PB5
  84. @SPI_SOF_CS_PB6 //注意使用PB6是仿真接口,在线仿真时该io口不能被使用
  85. @SPI_SOF_CS_PB7
  86. @SPI_SOF_CS_PC0
  87. @SPI_SOF_CS_PC1
  88. 返回:无
  89. */
  90. void SN_SPI_IO_SOF_cs(uint8_t SPI_SOF_CS_Px){
  91. std_gpio_init_t gpio_config = {0};
  92. uint32_t RCC_PERIPH_CLK_GPIOx = 0;
  93. 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; //时钟
  94. G_GPIO_X = (SPI_SOF_CS_Px < 9 ) ? GPIOA : ( SPI_SOF_CS_Px < 17) ? GPIOB : GPIOC; //端口
  95. 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)); //引脚
  96. //初始化
  97. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
  98. gpio_config.pin = G_GPIO_PIN_x; //选择IO编号
  99. gpio_config.mode = GPIO_MODE_OUTPUT; //设置为输出
  100. gpio_config.pull = GPIO_NOPULL; //无上下拉设置
  101. gpio_config.output_type = GPIO_OUTPUT_PUSHPULL; //推挽输出
  102. std_gpio_init(G_GPIO_X, &gpio_config); //初始
  103. //设置输出高
  104. std_gpio_set_pin(G_GPIO_X, G_GPIO_PIN_x); //设置cs为高,取消片选
  105. SN_SPI_CS_t.SN_SPI_CS_H = SN_SPI_SOF_CS_H ; //连接软件片选信号
  106. SN_SPI_CS_t.SN_SPI_CS_L = SN_SPI_SOF_CS_L ;
  107. }
  108. /*
  109. 函数: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)
  110. 参数:MOSI
  111. @SPI_MOSI_PA0
  112. @SPI_MOSI_PA7
  113. @SPI_MOSI_PB7
  114. 参数:MISO
  115. @SPI_MISO_PA1
  116. @SPI_MISO_PB6 (PB6是仿真接口,在线仿真时不要用)
  117. @SPI_MISO_PC1
  118. 参数:SCK
  119. @SPI_SCK_PA6
  120. @SPI_SCK_PB0
  121. @SPI_SCK_PB2
  122. 参数:NSS
  123. @SPI_NSS_NULL (不使用硬件片选,用户要自行设置软件cs使能调用)
  124. @SPI_NSS_PA6
  125. @SPI_NSS_PB0
  126. @SPI_NSS_PB2
  127. 返回:无
  128. */
  129. 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 ){
  130. //注意 spi初始化的 sck 电平
  131. std_gpio_init_t gpio_config = {0};
  132. uint32_t RCC_PERIPH_CLK_GPIOx = 0;
  133. GPIO_t * GPIO_X = NULL;
  134. uint16_t GPIO_PIN_x = 0;
  135. uint8_t GPIO_AF0_x = 0;
  136. //处理SPI_MOSI
  137. GPIO_AF0_x = GPIO_AF0_SPI1; //af复用选项
  138. GPIO_PIN_x = (SPI_MOSI_x == 1) ? GPIO_PIN_0 : GPIO_PIN_7 ; //设置引脚io
  139. GPIO_X = (SPI_MOSI_x != 3) ? GPIOA : GPIOB ; //设置io端口
  140. RCC_PERIPH_CLK_GPIOx = ( SPI_MOSI_x != 3) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB ; //设置时钟
  141. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
  142. gpio_config.pin = GPIO_PIN_x; //选择IO编号
  143. gpio_config.mode = GPIO_MODE_ALTERNATE; //设置为复用功能
  144. gpio_config.pull = GPIO_NOPULL; //无上下拉设置
  145. gpio_config.output_type = GPIO_OUTPUT_PUSHPULL; //推挽输出
  146. gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
  147. std_gpio_init(GPIO_X, &gpio_config); //初始
  148. //处理SPI_MISO
  149. GPIO_AF0_x = ( SPI_MISO_x != 2 ) ? GPIO_AF0_SPI1 : GPIO_AF4_SPI1 ; //af复用选项
  150. GPIO_PIN_x = ( SPI_MISO_x == 1 ) ? GPIO_PIN_1 : (( SPI_MISO_x == 2 ) ? ( GPIO_PIN_6 ): (GPIO_PIN_1 )) ; //设置引脚io
  151. GPIO_X = ( SPI_MISO_x == 1 ) ? GPIOA : (( SPI_MISO_x == 2 ) ? ( GPIOB ): ( GPIOC )) ; //设置io端口
  152. RCC_PERIPH_CLK_GPIOx = ( SPI_MISO_x == 1 ) ? RCC_PERIPH_CLK_GPIOA : (( SPI_MISO_x == 2 ) ? ( RCC_PERIPH_CLK_GPIOB): ( RCC_PERIPH_CLK_GPIOC )) ; //设置时钟
  153. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
  154. gpio_config.pin = GPIO_PIN_x ; //选择IO编号
  155. gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
  156. std_gpio_init(GPIO_X, &gpio_config); //初始
  157. //SPI_SCK
  158. GPIO_AF0_x = ( SPI_SCK_x == 1 ) ? GPIO_AF4_SPI1 : GPIO_AF0_SPI1 ; //af复用选项
  159. GPIO_PIN_x = ( SPI_SCK_x == 1 ) ? GPIO_PIN_6 : (( SPI_SCK_x == 2 ) ? ( GPIO_PIN_0 ): (GPIO_PIN_2 )) ; //设置引脚io
  160. GPIO_X = ( SPI_SCK_x == 1 ) ? GPIOA : GPIOB ; //设置io端口
  161. RCC_PERIPH_CLK_GPIOx = ( SPI_SCK_x == 1 ) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB; //设置时钟
  162. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
  163. gpio_config.pull = GPIO_PULLUP;
  164. gpio_config.pin = GPIO_PIN_x ; //选择IO编号
  165. gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
  166. std_gpio_init(GPIO_X, &gpio_config); //初始
  167. //SPI_NSS
  168. if(SPI_NSS_x != 1){
  169. GPIO_AF0_x = GPIO_AF0_SPI1; //af复用选项
  170. GPIO_PIN_x = ( SPI_NSS_x == 2 ) ? GPIO_PIN_6 : ( SPI_NSS_x == 3 ) ? GPIO_PIN_1 : GPIO_PIN_5 ; //设置引脚io
  171. GPIO_X = ( SPI_NSS_x == 2 ) ? GPIOA : GPIOB ; //设置io端口
  172. RCC_PERIPH_CLK_GPIOx = ( SPI_NSS_x == 2 ) ? RCC_PERIPH_CLK_GPIOA : RCC_PERIPH_CLK_GPIOB; //设置时钟
  173. std_rcc_gpio_clk_enable(RCC_PERIPH_CLK_GPIOx);
  174. gpio_config.pin = GPIO_PIN_x ; //选择IO编号
  175. gpio_config.alternate = GPIO_AF0_x; //选择复用模式为AF0_SPI1
  176. std_gpio_init(GPIO_X, &gpio_config); //初始
  177. }else{
  178. SPI_NSS_EN = 1; //设置全局标志,说明NSS引脚没被使用
  179. }
  180. }
  181. /*
  182. 函数:SN_SPI_MASTER_init(uint32_t SPI_DIV, uint8_t SPI_MODE_X , uint8_t SPI_MSB_OR_LSB )
  183. 参数:spi分频系数(分频系数)
  184. @SPI_BAUD_PCLKDIV_2 SPI速率为fPLCK/2 最高24M,系统时钟必须在48MHZ
  185. @SPI_BAUD_PCLKDIV_4 SPI速率为fPLCK/4
  186. @SPI_BAUD_PCLKDIV_8 SPI速率为fPLCK/8
  187. @SPI_BAUD_PCLKDIV_16 SPI速率为fPLCK/16
  188. @SPI_BAUD_PCLKDIV_32 SPI速率为fPLCK/32
  189. @SPI_BAUD_PCLKDIV_64 SPI速率为fPLCK/64
  190. @SPI_BAUD_PCLKDIV_128 SPI速率为fPLCK/128
  191. 参数:spi通信模式
  192. @SPI_MODE_0
  193. @SPI_MODE_1
  194. @SPI_MODE_2
  195. @SPI_MODE_3
  196. 参数:spi数据对齐选择
  197. @SPI_MSB
  198. @SPI_LSB
  199. 返回:无
  200. */
  201. void SN_SPI_MASTER_init(uint32_t SPI_DIV, uint8_t SPI_MODE_X , uint8_t SPI_MSB_OR_LSB ){
  202. uint32_t SPI_POLARIT_x = 0;
  203. uint32_t SPI_PHASE_x = 0;
  204. //处理spi模块
  205. std_spi_init_t spi_config = {0};
  206. /* SPI1时钟使能 */
  207. std_rcc_apb2_clk_enable(RCC_PERIPH_CLK_SPI1);
  208. /* 禁止SPI */
  209. std_spi_disable();
  210. /* SPI结构体初始化 使用SPI的00模式 */
  211. spi_config.mode = SPI_MODE_MASTER;
  212. spi_config.baud_rate_prescaler = SPI_DIV; //spi工作速率
  213. //设置spi模式
  214. SPI_POLARIT_x = ((SPI_MODE_X == 0) || (SPI_MODE_X == 1)) ? SPI_POLARITY_LOW : SPI_POLARITY_HIGH ;
  215. SPI_PHASE_x = ((SPI_MODE_X == 0) || (SPI_MODE_X == 2)) ? SPI_PHASE_1EDGE : SPI_PHASE_2EDGE ;
  216. spi_config.clk_polarity = SPI_POLARIT_x; //时钟空闲下为高电平
  217. spi_config.clk_phase = SPI_PHASE_x; //第一个时钟边沿采样
  218. spi_config.bitorder = SPI_MSB_OR_LSB; //先发高位
  219. std_spi_init(&spi_config); //初始化参数
  220. /* SPI主机模式,配置NSS输出使能 */
  221. if(SPI_NSS_EN == 0 ){
  222. std_spi_nss_output_enable();
  223. SN_SPI_CS_t.SN_SPI_CS_H = NULL;
  224. SN_SPI_CS_t.SN_SPI_CS_L = NULL;
  225. }
  226. /* SPI使能 */
  227. std_spi_enable(); //使能SPI
  228. }
  229. /*
  230. 函数:SN_SPI_TX_RX(uint8_t * send_data ,uint8_t * read_data ,uint16_t len)
  231. 功能:通过spi发送数据
  232. 参数:发送数组
  233. 参数:数组长度
  234. 返回: 无
  235. */
  236. void SN_SPI_TX_RX(uint8_t * send_data ,uint8_t * read_data ,uint16_t len){
  237. uint16_t index = 0;
  238. /* SPI主机模式,拉低片选信号 */
  239. if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); }
  240. std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW);
  241. /* SPI数据传输 */
  242. for(index=0; index<len; index++)
  243. {
  244. /* 等待发送数据寄存器为空 */
  245. while(std_spi_get_flag(SPI_FLAG_TXFE) != SPI_FLAG_TXFE);
  246. /* 发送数据 */
  247. std_spi_write_data(send_data[index]);
  248. /* 等待接收数据寄存器非空 */
  249. while(std_spi_get_flag(SPI_FLAG_RXFNE) != SPI_FLAG_RXFNE);
  250. /* 接收数据 */
  251. read_data[index] = std_spi_read_data();
  252. }
  253. /* SPI主机拉高片选信号,结束通信 */
  254. while(!std_spi_get_flag(SPI_FLAG_TXFE));
  255. while(std_spi_get_flag(SPI_FLAG_BUSY));
  256. /* SPI主机模式,拉高片选信号 */
  257. if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_H(); }
  258. std_spi_set_nss_output(SPI_NSS_OUTPUT_HIGH);
  259. }
  260. /*
  261. 函数:SN_SPI_TX(uint8_t * send_data ,uint16_t len)
  262. 功能:通过spi发送数据
  263. 参数:发送数组
  264. 参数:数组长度
  265. 返回: 无
  266. */
  267. void SN_SPI_TX(uint8_t * send_data ,uint16_t len){
  268. uint16_t index = 0;
  269. /* SPI主机模式,拉低片选信号 */
  270. if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); }
  271. std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW);
  272. /* SPI数据传输 */
  273. for(index=0; index<len; index++)
  274. {
  275. /* 等待发送数据寄存器为空 */
  276. while(std_spi_get_flag(SPI_FLAG_TXFE) != SPI_FLAG_TXFE);
  277. /* 发送数据 */
  278. std_spi_write_data(send_data[index]);
  279. /* 等待接收数据寄存器非空 */
  280. while(std_spi_get_flag(SPI_FLAG_RXFNE) != SPI_FLAG_RXFNE);
  281. /* 接收数据 */
  282. std_spi_read_data(); //丢弃接收数据
  283. }
  284. /* SPI主机拉高片选信号,结束通信 */
  285. while(!std_spi_get_flag(SPI_FLAG_TXFE));
  286. while(std_spi_get_flag(SPI_FLAG_BUSY));
  287. /* SPI主机模式,拉高片选信号 */
  288. if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_H(); }
  289. std_spi_set_nss_output(SPI_NSS_OUTPUT_HIGH);
  290. }
  291. /*
  292. 函数:SN_SPI_RX(uint8_t * read_data ,uint16_t len)
  293. 功能:通过spi接收数据
  294. 参数:发送数组
  295. 参数:数组长度
  296. 返回: 无
  297. */
  298. void SN_SPI_RX(uint8_t * read_data ,uint16_t len){
  299. uint16_t index = 0;
  300. /* SPI主机模式,拉低片选信号 */
  301. if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_L(); }
  302. std_spi_set_nss_output(SPI_NSS_OUTPUT_LOW);
  303. /* SPI数据传输 */
  304. for(index=0; index<len; index++)
  305. {
  306. /* 等待发送数据寄存器为空 */
  307. while(std_spi_get_flag(SPI_FLAG_TXFE) != SPI_FLAG_TXFE);
  308. /* 发送数据 */
  309. std_spi_write_data(0x00); //推空数据出去
  310. /* 等待接收数据寄存器非空 */
  311. while(std_spi_get_flag(SPI_FLAG_RXFNE) != SPI_FLAG_RXFNE);
  312. /* 接收数据 */
  313. read_data[index] = std_spi_read_data();
  314. }
  315. /* SPI主机拉高片选信号,结束通信 */
  316. while(!std_spi_get_flag(SPI_FLAG_TXFE));
  317. while(std_spi_get_flag(SPI_FLAG_BUSY));
  318. /* SPI主机模式,拉高片选信号 */
  319. if(SPI_NSS_EN == 1 ){ SN_SPI_CS_t.SN_SPI_CS_H(); }
  320. std_spi_set_nss_output(SPI_NSS_OUTPUT_HIGH);
  321. }