因为软件模拟的方式,io翻转和条件判断时间过长,不能满足归零码的时序,只能采用DMA+SPI硬件传输的方式。
SPI配置,因为只使用mosi模拟单极性归零码,所以直接把SPI的4个脚直接配置成复用模式,nss配置为soft或hard都能用,没有影响
注意LF配置(.endian),endian为MSB(高位先发)。因为归零码要求低电平复位,因此可在发送数组中多加一位,固定发0x00,空闲时就是低电平了。
void SPI0_config()
{
spi_parameter_struct spi_init_struct;
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_SPI1);
//端口直接配置为复用模式,GPIO_PUPD_PULLDOWN或GPIO_PUPD_NONE没区别
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLDOWN,GPIO_PIN_12 | GPIO_PIN_13 |
GPIO_PIN_14 | GPIO_PIN_15);
gpio_af_set(GPIOB, GPIO_AF_0,GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ,GPIO_PIN_12 |
GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
spi_init_struct.trans_mode = SPI_TRANSMODE_BDTRANSMIT;//SPI_TRANSMODE_FULLDUPLEX;//
spi_init_struct.device_mode = SPI_MASTER;
spi_init_struct.frame_size = SPI_FRAMESIZE_8BIT;
spi_init_struct.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE;
spi_init_struct.nss = SPI_NSS_SOFT;//SPI_NSS_HARD;//
spi_init_struct.prescale = SPI_PSC_8;
spi_init_struct.endian = SPI_ENDIAN_MSB;
spi_init(SPI1, &spi_init_struct);
spi_dma_enable(SPI1,SPI_DMA_TRANSMIT); //发送使用dma
spi_crc_polynomial_set(SPI1, 7);
spi_enable(SPI1);
}
DMA配置,配置结束不急着开启
void SPI_DMA_config(void)
{
dma_parameter_struct dma_init_struct;
rcu_periph_clock_enable(RCU_DMA);
dma_struct_para_init(&dma_init_struct);
dma_deinit(DMA_CH4);
dma_struct_para_init(&dma_init_struct);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
dma_init_struct.memory_addr = (uint32_t)sendbuff;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE; //内存递增
dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
dma_init_struct.number = RGB_SEND_SIZE;
dma_init_struct.periph_addr = (uint32_t)&SPI_DATA(SPI1); //注意&符号
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE; //外设不递增
dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_init(DMA_CH4, &dma_init_struct);
dma_memory_to_memory_disable(DMA_CH4);
dma_circulation_disable(DMA_CH4);
dma_interrupt_disable(DMA_CH4, DMA_INT_FTF);
// dma_channel_enable(DMA_CH4); //使能关闭,发送前开启
}
发送流程,DMA启动SPI发送的流程为,先配置好SPI(只需要一次),再配置好DMA(每次发送前都要配置,配置好自动发送)就可以了。
其实每次DMA启动只需要部分配置参数,这里为了省事直接调用初始化配置函数。
void spi_dma_send(void)
{
dma_channel_disable(DMA_CH4);
SPI_DMA_config();
dma_channel_enable(DMA_CH4);
while(RESET == dma_flag_get(DMA_CH4,DMA_FLAG_FTF));
}
发送前将数据更新到DMA配置的内存地址中就OK了。
memcpy(sendbuff,sendbuff,SEND_SIZE); //第一个sendbuff是全局变量,第二个是局部变量
spi_dma_send();
模拟归零码的原理就是,调整SPI周期,使得SPI传输8个字节的时间约等于归零码一个高-低电平周期的时间,这样控制SPI发送的1个字节的数据,相当于传输归零码1位的数据。下面是SPI总线42Mhz,8分频之后归零码0、1对应的spi字节宏定义,SPI发送1位数据大约0.2us,要求严格的话,也可以配置成4分频,采用16字节数据传输,根据需求合理配置。
#define lowbit 0x80
#define highbit 0xf8