STM32F407 通过SPI接口驱动MCP42100
MCP42100是具有两路数字电位器,两路数字电位器block diagram 如下
主机和MCP42100 通过SPI硬件接口进行通信.
MCP操作时序图.
问题描述
两路电位器连续写的时候会发现第二路写不成功的现象,但是单独一路操作是正常的,都可进行.连续使用SpiWriteUnitTest()函数分别给0 和1 电位器写的时候就会出现第二个电位器写不进去.
代码如下:
SPI初始化代码:
void SpiInit()
{
uint32_t i;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB
| RCC_AHB1Periph_GPIOC
| RCC_AHB1Periph_GPIOD, ENABLE);// 时钟使能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_SPI2);// PB13 复用为SPI2接口
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_SPI2);//同上
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 // PB13 SCLK
| GPIO_Pin_15; // PB15 MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SPI_InitTypeDef SPI_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
SPI_I2S_DeInit(SPI2);
SPI_InitStruct.SPI_Direction = SPI_Direction_1Line_Tx; //单向发送
SPI_InitStruct.SPI_Mode = SPI_Mode_Master;
SPI_InitStruct.SPI_DataSize = SPI_DataSize_16b;
SPI_InitStruct.SPI_CPOL = SPI_CPOL_High; // SPI_CPOL_Low
SPI_InitStruct.SPI_CPHA = SPI_CPHA_2Edge ;//SPI_CPHA_1Edge
SPI_InitStruct.SPI_NSS = SPI_NSS_Soft;
SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;//
SPI_InitStruct.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStruct.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStruct);
SPI_Cmd(SPI2, ENABLE);//使能SPI2
}
SPIwrite data 代码:
void SpiWriteUnitTest(uint8_t a_chan, uint8_t a_value)
{
GPIO_ResetBits(GPIOC, GPIO_Pin_12);//cs enable
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);
if (0 == a_chan)
{
SPI_I2S_SendData(SPI2, 0x1100 | a_value);
}
else if (1 == a_chan)
{
SPI_I2S_SendData(SPI2, 0x1200 | a_value);
}
else if(2 == a_chan)
{
SPI_I2S_SendData(SPI2, 0x1300 | a_value);
}
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
SPI_I2S_ReceiveData(SPI2); //need read ,otherwise continue write next will fail,however i don't kow why ~ ~
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
GPIO_SetBits(GPIOC, GPIO_Pin_12);//cs disable
return;
}
此项目使用的是SPI只写,硬件仅需三根线,SCK,CS,MOSI,硬件未连接MISO信号线.
SPI四种模式
我们SPI通信有4种不同的模式,不同的从设备可能在出厂是就是配
置为某种模式,这是不能改变的;但我们的通信双方必须是工作在同一模式下,所以我们
可以对我们的主设备的SPI模式进行配置,通过CPOL(时钟极性)和CPHA(时钟相位)来
控制我们主设备的通信模式,具体如下:
Mode0:CPOL=0,CPHA=0
Mode1:CPOL=0,CPHA=1
Mode2:CPOL=1,CPHA=0
Mode3:CPOL=1,CPHA=1
时钟极性CPOL是用来配置SCLK的电平出于哪种状态时是空闲态或者有效态,时钟相位CPHA
是用来配置数据采样是在第几个边沿:
CPOL=0,表示当SCLK=0时处于空闲态,所以有效状态就是SCLK处于高电平时
CPOL=1,表示当SCLK=1时处于空闲态,所以有效状态就是SCLK处于低电平时
CPHA=0,表示数据采样是在第1个边沿,数据发送在第2个边沿
CPHA=1,表示数据采样是在第2个边沿,数据发送在第1个边沿
例如:
CPOL=0,CPHA=0:此时空闲态时,SCLK处于低电平,数据采样是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在上升沿,数据发送是在下降沿。
CPOL=0,CPHA=1:此时空闲态时,SCLK处于低电平,数据发送是在第1个边沿,也就是
SCLK由低电平到高电平的跳变,所以数据采样是在下降沿,数据发送是在上升沿。
CPOL=1,CPHA=0:此时空闲态时,SCLK处于高电平,数据采集是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在下降沿,数据发送是在上升沿。
CPOL=1,CPHA=1:此时空闲态时,SCLK处于高电平,数据发送是在第1个边沿,也就是
SCLK由高电平到低电平的跳变,所以数据采集是在上升沿,数据发送是在下降沿。
我们此项目使用的是Mode3这个根据MCP42100的时序可以看到Mode3符合MCP42100的时序.
解决方案:
如下是硬件电路图:
同时写两路的电位器的时候总是第二次写的电位器写不进去,当时思考两种方案
- 写两遍的做法,此方法可以正确写入两路,因此怀疑时许存在问题,
- 写完后实验主机进行读取一次操作.发现一次就可写成功.
因此使用第二个做法在写完后调用读取函数进行读取操作. 执行如下代码即可成功进行操作.
SPI_I2S_ReceiveData(SPI2); //need read ,otherwise continue write next data will fail,however i don't kow why ~ ~
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);
总结
以上就是我在调试stm32 SPI接口和MCP402100数字电位器的过程中遇到的问题,在此作为借鉴,若有错误望大家指出.共同进步,成长为一名完美的嵌入式工程师是我们的终极目标,…