CMS32L051 SPI分享

编程入门 行业动态 更新时间:2024-10-10 05:24:58

CMS32L051 <a href=https://www.elefans.com/category/jswz/34/1768562.html style=SPI分享"/>

CMS32L051 SPI分享

CMS32L051 SPI分享

目录

  • CMS32L051 SPI分享
  • 一、SPI是什么?
  • 二、I/O模拟SPI
    • 1.SPI的本质
  • 二、硬件SPI
    • 1.SPI从机模式初始化
  • 总结
  • 项目源码链接


–前言
前几天做了个项目用到了CMS32L051这款芯片,需要用SPI去读取传感器的数据并通过SPI转发给上位机。
读取传感器的SPI采用了用I/O(引脚)模拟的方式去实现的SPI通信,而与上位机的通信调用的是芯片本身硬件的SPI。
所以本文前半部分分享的是I/O模拟SPI的流程及代码,后半部分分享如何通过初始化相关寄存器来实现SPI通信。

一、SPI是什么?

SPI的详细解释我就不过多赘述了,网上的相关介绍还是非常详尽的。
我就针对四根线的具体含义解释一下(为模拟SPI铺垫一下):

  • SSN(片选):从设备使能信号,由主设备控制(本质上就是主机发送下拉信号)。
  • SCK(时钟):时钟信号,由主设备产生(本质上就是连续的下拉上拉信号)。
  • MISO:M主机S从机 I输入O输出(数据传输的本质也是高低电平 )。
  • MOSI:M主机S从机 I输入O输出(例如0x83 1000 0011 高电平为1低电平为0)。

二、I/O模拟SPI

1.SPI的本质

从我上文的铺垫可以看出,不管SSN信号、SCK时钟还是数据本质上都是高低电平的组合。这就给我们通过I/O去模拟SPI提供了事实基础。让我们来看一下SPI的时序图。
模拟SPI读取MT6815(磁性旋转编码器芯片)的流程为:
发送读取命令0x83,接收03寄存器的数据,发送读取命令0x84,接收04寄存器的数据。
让我们结合代码来看一看I/O模拟是怎么实现的

#define  SPI_OUTPUT_ENABLE() GPIO_Output_Enable(&PORT->P7, 0x1C)  // 0001 1100 P72 P73 P74 输出使能
#define  SPI_INPUT_ENABLE()  PORT_Init( PORT7, PIN4, PULLDOWN_INPUT);  //P74 默认上拉输入 需要设置为下拉输入#define  SET_SPI_CSN()     GPIO_Set_Value(&PORT->P7, GPIO_Get_Value(&PORT->P7) | 0x04 )  //P72   CSN 置1
#define  RESET_SPI_CSN()   GPIO_Set_Value(&PORT->P7, GPIO_Get_Value(&PORT->P7) & ~0x04 ) //P72   CSN 置0
#define  SET_SPI_SCK()     GPIO_Set_Value(&PORT->P7, GPIO_Get_Value(&PORT->P7) | 0x08 )  //P73   SCK 置1
#define  RESET_SPI_SCK()   GPIO_Set_Value(&PORT->P7, GPIO_Get_Value(&PORT->P7) & ~0x08 ) //P73   SCK 置0
#define  SET_SPI_SDAT()    GPIO_Set_Value(&PORT->P7, GPIO_Get_Value(&PORT->P7) | 0x10 )  //P74  SDAT 置1
#define  RESET_SPI_SDAT()  GPIO_Set_Value(&PORT->P7, GPIO_Get_Value(&PORT->P7) & ~0x10)  //P74  SDAT 置0static unsigned short  s_usSPI_Data[3];unsigned short  Read_Magnetic_Encode(void)   //产生clk信号,发送数据和接收数据
{unsigned char i;unsigned short j;s_usSPI_Data[0] = 0; //j =0x84;             //待发送的数据SPI_OUTPUT_ENABLE(); //P72 P73 P74 输出使能 SDAT为输出 准备发送读的命令0x83RESET_SPI_CSN();     //P72  CSN 拉低 发送开始前线拉低片选信号for(i = 0;i< 8;i ++) //为了不占太多行就if一句话的不加花括号了{RESET_SPI_SCK();   //P73  SCK 拉低   if(j&0x80)         //如果待发送的是1 就把P74数据线置高SET_SPI_SDAT();   //P74  SDAT 拉高 else               //否则 就把P74数据线置低RESET_SPI_SDAT(); //P74  SDAT 拉低j <<= 1;           //发完一位数据发下一位数据SET_SPI_SCK();     //P73  SCK 拉高} //发送完读的命令(0x83) 切换SDAT为输入 准备接收数据SPI_INPUT_ENABLE();   //P74 输入使能for(i = 0;i< 8;i ++){RESET_SPI_SCK();   //P73  SCK 拉低s_usSPI_Data[0] <<= 1;if( (GPIO_Get_Value(&PORT->P7) & 1 << 4) != 0 ) //P74 SDAT 输入不为零s_usSPI_Data[0] += 1;SET_SPI_SCK();     //P73  SCK 拉高}SET_SPI_CSN();       //P72  CSN 拉高SPI_OUTPUT_ENABLE(); //P72 P73 P74 输出使能 SDAT为输出 准备发送读的命令0x84/************** 第二遍发送 接收 *************/j = 0x84;RESET_SPI_CSN();     //P72  CSN 拉低 发送开始前线拉低片选信号for(i = 0;i< 8;i ++) //为了不占太多行就if一句话的不加花括号了{RESET_SPI_SCK();   //P73  SCK 拉低   if(j&0x80)         //如果待发送的是1 就把P74数据线置高SET_SPI_SDAT();   //P74  SDAT 拉高 else               //否则 就把P74数据线置低RESET_SPI_SDAT(); //P74  SDAT 拉低j <<= 1;           //发完一位数据发下一位数据SET_SPI_SCK();     //P73  SCK 拉高} //发送完读的命令(0x83) 切换SDAT为输入 准备接收数据SPI_INPUT_ENABLE();   //P74 输入使能for(i = 0;i< 8;i ++){RESET_SPI_SCK();   //P73  SCK 拉低s_usSPI_Data[0] <<= 1;if( (GPIO_Get_Value(&PORT->P7) & 1 << 4) != 0 ) //P74 SDAT 输入不为零s_usSPI_Data[0] += 1;SET_SPI_SCK();     //P73  SCK 拉高}SET_SPI_CSN();       //P72  CSN 拉高
}

最后展示一下I/O模拟SPI的波形图


二、硬件SPI

1.SPI从机模式初始化

让我们翻看一下CMS32L051用户手册第13章 串行接口SPI。
13.4.3从属的发送和接收

废话不多说上代码

void SPI_SlaveInit(spi_mode_t mode)
{
//Clock Generate Control (CGC)//PER1 0x0000041A)外设使能寄存器1  PER10 外围设备启用寄存器0CGC->PER1 |= 0x80; // 提供SPI的输入时钟的控制    ***步骤 1***
//串行接口SPI (SPI) SPIC SPI控制寄存器  (0x0007U) /* 从SCK输入的外部时钟*/SPI->SPIC = _0007_SPI_SLAVE_MODE | (~mode & 0x03) << 3; //***步骤 2** **步骤 3***//SPI->SPIC = _0007_SPI_SLAVE_MODE | ( 0x03 ) << 3; 
//SPIM 0x00000000) SPI模式控制寄存器 // (0x0040U) transmission/reception                    buffer empty interrupt  (0x0004U) 16-bit data lengthSPI->SPIM = _0040_SPI_RECEPTION_TRANSMISSION | _0000_SPI_MSB |  _0008_SPI_BUFFER_EMPTY | _0004_SPI_LENGTH_16| _0080_SPI_START_TRG_ON;  // | _0020_SPI_NSS_ENABLE | _0080_SPI_START_TRG_ON;//***步骤 4***PORT->SPIPCFG = 0x01; //将SPI通信兼用功能映射到 P50 P51 P16 P17NSS_PORT_SETTING();  // P50  NSS 输入 SCK_PORT_SETTING();  // P51  SCK 输入MOSI_PORT_SETTING(); //P16  M0SI    从机输入MISO_PORT_SETTING(); //P17  MISO    从机输出
//  结束初始设定如果给SDRO寄存器设定发送数据,  等待主控设备的时钟SPI->SDRO = 0x0000;}int main()
{uint32_t msCnt;  // count value of 1msSystemCoreClockUpdata();msCnt = SystemCoreClock /1000 ;SysTick_Config(msCnt);
}int main()
{uint32_t msCnt;  // count value of 1ms//Systick setting  相关性不强的系统配置按下不表SPI_SlaveInit(SPI_MODE_2); //SPI初始化 选模式二 即CPOL=1(极性),CPHA=0(相位)//关于极性和相位的具体含义大家可以自行搜索 //我参考的是这篇文章 (&PORT->P1,GPIO_Get_Value(&PORT->P1) | 0x04 ); //P12 输出使能GPIO_Set_Value(&PORT->P1,GPIO_Get_Value(&PORT->P1) | 0x04 ); //P12置高 点灯while(1){if((GPIO_Get_Value(&PORT->P5) == 0x02) //等待CS P50 下拉信号{GPIO_Set_Value( &PORT->P1, GPIO_Get_Value(&PORT->P1) & ~0x80 ); //P17//拉低(MISO) 这也是我被坑的最惨地方 在CS下拉信号之后竟然还需要给MISO一个下触发信号//这还是我乱试试出来的 完全不合逻辑的操作折磨了我一个星期while( (GPIO_Get_Value(&PORT->P5) & 0x01 )== 0x00)//CS 下拉信号持续时间{ //主机在拿取 SPI->SDRO(发送缓冲寄存器) 中的数据}if((GPIO_Get_Value(&PORT->P5) == 0x03) //CS 下拉信号结束 从机数据发送完毕{SPI->SDRO = Read_Magnetic_Encode(); //将模拟SPI接收的数据赋给SDRO 等待下一次CS的下拉信号发送给主机}}//if}//while}//main

总结

  • 相对于硬件SPI , I/O模拟SPI的优势在于不需要了解芯片SPI的相关配置寄存器 。只要求掌握基础的GPIO输入与输出 和 SPI时序有一定的了解,在有现成的 时序逻辑代码 后移植起来非常的轻松。
  • 相比于I/O模拟SPI 硬件SPI的优势在于:
    1 输出的波形比较标准,抗干扰能力相较于I/O模拟SPI更强;
    2只需要配置好相关的寄存器,数据的收发将会无比轻松,只需要 读写 相关的 发送(SDRO)接收(SDRI)寄存器 。难点在于SPI的初始化配置。

项目源码链接

阿里云盘:「6816磁性编码器项目」 提取码: 4m8c
百度网盘:链接: 提取码:accg

更多推荐

CMS32L051 SPI分享

本文发布于:2024-02-13 07:00:23,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1757532.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:SPI

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!