苏州行业网站建设报价免费十八种禁用网站
0x00前言
因为前文有说到对于HC32F460的相关引脚测试,笔者最近完成了一个按照器件化简化的SPI的总线,所以放在MCU上测试一下效果。
0x10 介绍
作为一个SPI模拟器,他至少需要:
- 一个设置的方式
- 一个查看当前状态的接口
- 一个写入接口
- 一个读取接口
前文介绍过SPI的特性,这里不再赘述:
typedef union
{unsigned char d8;struct{unsigned CPHA:1; //0-even-catch|1-odd-catchunsigned CPOL:1; //0-low|1-highunsigned DATASIZE:1; //0-8bit|1-16bitunsigned FLASH_BIT:1; //0-MSB|1-LSBunsigned MODE:1; //0-master|1-slaveunsigned DIR:2; //0-Full duplex|1-onlyRX|2-onlyTX|3-Only_listenunsigned ENABLE :1; //0-off|1-on}b;}S_SPI_CONFIG;
typedef struct
{unsigned CLK:1;unsigned CS:1; unsigned MOSI:1; unsigned MISO:1; unsigned NU :28;
}S_SPI_SOFT_PIN;
这就是当前的虚拟设备的模式与引脚建模,这里只实现了Master、Mode 0模式,剩下的模式没有测试
这里HC32F460库没有对于当前GPIO单个驱动的接口,所以笔者自己做了一个
void Port_Write_Pins(en_port_t enPort, uint16_t u16Pin,unsigned char state)
{uint16_t *PORx;if(state){PORx = (uint16_t *)((uint32_t)(&M4_PORT->POSRA) + 0x10u * enPort);}else{PORx = (uint16_t *)((uint32_t)(&M4_PORT->PORRA) + 0x10u * enPort);}*PORx |= u16Pin;
}
下面还需要一个基本的实现,也就是使用一个定时器的模型进行模拟当前的SPI设备:
void TIM_IRQHandler(){{if(spi_soft_obj.config.b.ENABLE == 1){//normal-no sendif(spi_soft_obj.line_state == 0){if(spi_soft_obj.config.b.CPOL){spi_pin.CLK = 1;}else{spi_pin.CLK = 0;}//spi_pin.MOSI = 0;if(spi_pin.CS == 1){//MSBif(spi_soft_obj.config.b.FLASH_BIT == 0){spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET();}//LSBelse{ //no debugspi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET()<<((8*(spi_soft_obj.config.b.DATASIZE+1)));}}spi_pin.CS = 0;update_bit =0;clock_count = 0;spi_bit_count = 0;}//send-once byteelse{if((clock_count == 0)){spi_soft_obj.data[SOFT_SPI_DATA_IN] = 0;}//0-CPHA=0 if((!spi_soft_obj.config.b.CPHA) && (clock_count == 0)){update_bit = 1;spi_pin.CLK = 0;}else{spi_pin.CLK = !spi_pin.CLK;if((clock_count % 2) == (spi_soft_obj.config.b.CPHA)){update_bit = 1;}elseupdate_bit = 0;}clock_count++;//send_finishif((8*(spi_soft_obj.config.b.DATASIZE+1)) <= spi_bit_count){spi_soft_obj.line_state = 0;//spi_pin.MOSI = 0;spi_pin.CS = 1;update_bit =0;clock_count = 0;spi_bit_count = 0;}if(update_bit){spi_pin.MISO = MISO_GET();//MSBif(spi_soft_obj.config.b.FLASH_BIT == 0){spi_pin.MOSI = spi_soft_obj.data[SOFT_SPI_DATA_OUT] >> ((8*(spi_soft_obj.config.b.DATASIZE+1)) - spi_bit_count - 1 ) & 0x01;spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET()<<((8*(spi_soft_obj.config.b.DATASIZE+1))- spi_bit_count );}//LSBelse{ //no debugspi_pin.MOSI = spi_soft_obj.data[SOFT_SPI_DATA_OUT] >> (spi_bit_count) & 0x01;spi_soft_obj.data[SOFT_SPI_DATA_IN] |= MISO_GET()<<(spi_bit_count);}spi_bit_count++;}}CLK_SET(spi_pin.CLK);MOSI_SET(spi_pin.MOSI);}else{CLK_SET(0);MOSI_SET(0);}}}
这里就已经得到了一个基本的器件模拟化的代码。只要接入定时器的接口就可以直接实现SPI的通信了。这里笔者选择了PB 6 7 8 9作为IO的端口
void spi_soft_init(){stc_port_init_t port_init_struct;port_init_struct.enPinMode = Pin_Mode_Out;port_init_struct.enPullUp = Enable;port_init_struct.enLatch = Disable;port_init_struct.enExInt = Disable;port_init_struct.enInvert = Disable;port_init_struct.enPullUp = Enable;port_init_struct.enPinDrv = Pin_Drv_H;port_init_struct.enPinOType = Pin_OType_Cmos;port_init_struct.enPinSubFunc = Enable;PORT_Init(PortB, Pin06, &port_init_struct);PORT_Init(PortB, Pin07, &port_init_struct);PORT_Init(PortB, Pin08, &port_init_struct);port_init_struct.enPinMode = Pin_Mode_In;port_init_struct.enPinOType = Pin_OType_Od;port_init_struct.enPullUp = Disable;PORT_Init(PortB, Pin09, &port_init_struct);//PORT_SetFunc(PortA,Pin05, Func_Tima0, Enable);//TIM -- 模拟当前的频率spi_soft_obj.config.b.ENABLE = 1;timer_id = timer_add(0,0,0,0,0,1,0,1,0,TIM_IRQHandler);}
现在还不知道到底哪个端口做什么工作。于是笔者在这里使用宏定义进行约束,也方便后期维护,这里只是示例,也可以进行更精确的GPIO的宏定义替换。
#define CS_HIGH do{PORT_SetBits(PortB, Pin06);}while(0)
#define CS_LOW do{PORT_ResetBits(PortB, Pin06);}while(0)#define CLK_SET(state) do{Port_Write_Pins(PortB, Pin07, state);}while(0)#define MOSI_SET(state) do{Port_Write_Pins(PortB, Pin08, state);}while(0)
#define MISO_GET() (PORT_GetBit(PortB,Pin09))
最后,就是外部需要的接口了:
char SPI_GetBusBusy()
{while(spi_pin.CS || spi_soft_obj.line_state);return spi_pin.CS && spi_soft_obj.line_state;
}void SPI_SendData(unsigned short data)
{if((spi_soft_obj.config.b.ENABLE) && (!spi_soft_obj.config.b.MODE))spi_soft_obj.data[SOFT_SPI_DATA_OUT] = data;spi_soft_obj.line_state = 1;
}unsigned short SPI_ReceiveData()
{unsigned short data = 0x00;data = spi_soft_obj.data[SOFT_SPI_DATA_IN];spi_soft_obj.data[SOFT_SPI_DATA_IN] = 0;return data;
}
这样就完成了一个SPI器件的建模。替换引脚只需要替换宏定义与初始化的引脚位置即可。
笔者使用梦源的逻辑分析仪就可以直接得到现在的测试结果,下图是25KHz的具体情况
可以看到,当前字符累加结果无误,可以使用。
0x20 总结
本文首发自 记:模拟SPI的相关介绍与实际效果,更多文章可进入我的博客详查。