打印

gd32f303 spi+dma发送时D/C数据引脚超前启动了,导致不能传输

[复制链接]
560|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 优品科技 于 2023-4-20 15:27 编辑

C:\Users\14532\Desktop\QQ图片20230420152258.png

使用特权

评论回复
沙发
优品科技|  楼主 | 2023-4-20 15:25 | 只看该作者



使用特权

评论回复
评论
优品科技 2023-4-20 15:26 回复TA
3是DC引脚,1是时钟,0是mosi 
板凳
优品科技|  楼主 | 2023-4-20 15:29 | 只看该作者

使用特权

评论回复
评论
优品科技 2023-4-20 15:31 回复TA
这是正常的spi写屏的逻辑分析仪数据 
地板
优品科技|  楼主 | 2023-4-20 15:35 | 只看该作者
#include "gd32f30x.h"
#include "gd32f307c_eval.h"
#include "systick.h"
#include "oled.h"

#define CS_Clr() gpio_bit_reset(GPIOA,GPIO_PIN_4)     //cs PA4
#define CS_Set() gpio_bit_set(GPIOA,GPIO_PIN_4)

#define DC_Clr() gpio_bit_reset(GPIOB,GPIO_PIN_1)      //dc  PB1
#define DC_Set() gpio_bit_set(GPIOB,GPIO_PIN_1)

#define RST_Clr() gpio_bit_reset(GPIOB,GPIO_PIN_0)     //RES PB0
#define RST_Set() gpio_bit_set(GPIOB,GPIO_PIN_0)


uint8_t SPI_TX_BUF[4] = {0x9F,0xFF,0xFF,0xFF};
uint8_t spi0_receive_array[ARRAYSIZE];

uint16_t le1=1;
uint16_t sj1[2]={0xB1,0x22};
uint8_t Parameter=1;
uint8_t Command=0;


void DMASPI0_config(void)  //DMA
{
          rcu_periph_clock_enable(RCU_DMA0);
    dma_parameter_struct dma_init_struct;

    /* SPI0 transmit dma config:DMA0-DMA_CH2  */
    dma_deinit(DMA0, DMA_CH2);
    dma_init_struct.periph_addr  = (uint32_t)(&SPI_DATA(SPI0));
    dma_init_struct.memory_addr  = (uint32_t)SPI_TX_BUF;         //发送的数据地址,定义一个数组
    dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;    //内存搬到外设
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_LOW;
    dma_init_struct.number       = ARRAYSIZE;                          //发送的字符数据个数,(0x02,0x25)就是2个数据
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init(DMA0, DMA_CH2, &dma_init_struct);
    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH2);
    dma_memory_to_memory_disable(DMA0, DMA_CH2);
    dma_channel_enable(DMA0, DMA_CH2);
       
}


void spi_config(void)               //初始化spi0
{
   rcu_periph_clock_enable(RCU_GPIOB);
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_AF);
    rcu_periph_clock_enable(RCU_SPI1);
  spi_parameter_struct spi_init_struct;
    /* deinitilize SPI and the parameters */

    spi_struct_para_init(&spi_init_struct);

    /* SPI0 parameter config */
    spi_init_struct.trans_mode           = SPI_TRANSMODE_FULLDUPLEX;   // 全双工模式  SPI_TRANSMODE_BDTRANSMIT   SPI_TRANSMODE_FULLDUPLEX
    spi_init_struct.device_mode          = SPI_MASTER;                 // 主机模式
    spi_init_struct.frame_size           = SPI_FRAMESIZE_8BIT;         // spi使用8位数据帧格式
    spi_init_struct.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE;    // 在spi为空闲状态时,clk时钟引脚拉低,时钟的第二个跳变沿开始采集数据  SPI_CK_PL_HIGH_PH_2EDGE
    spi_init_struct.nss                  = SPI_NSS_SOFT;
    spi_init_struct.prescale             = SPI_PSC_8;                   //分频设置108/8=13.5m
    spi_init_struct.endian               = SPI_ENDIAN_MSB;              // 先发送最高位
    spi_init(SPI0, &spi_init_struct);           // 使用spi_init_struct结构参数初始化spi0

        spi_crc_polynomial_set(SPI1,7);             // 把7写入主机的crc多项式寄存器
        spi_enable(SPI0);                          // 使能spi
}



void gpio_config(void)
{
       
           rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);
    /* SPI0 GPIO config: SCK/PA5, MISO/PA6, MOSI/PA7 */
    gpio_init(GPIOA, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5 | GPIO_PIN_7);
    gpio_init(GPIOA, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
       
    /* PA4 as cs片选 pb0是reset,pb1是d/c*/
  gpio_init(GPIOA, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_4);
        gpio_init(GPIOB, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0| GPIO_PIN_1);

       
        RST_Set();
}

void LCD_Writ_Bus(uint8_t dat)
{
           CS_Clr();

        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_TBE));
        spi_i2s_data_transmit(SPI0, dat);
        while(RESET == spi_i2s_flag_get(SPI0, SPI_FLAG_RBNE));
       spi_i2s_data_receive(SPI0);
//        DMASPI0_write_8(&dat,1);         现在是硬件spi,如果将这行取消注释并把上面四行注释就切换成了spi+dma,这时DC引脚就会时序不正常
       
     CS_Set();
}

void LCD_WR_DATA8(uint8_t dat)
{
        DC_Set();//Write data
        LCD_Writ_Bus(dat);
       
        //DMASPI0_write((uint16_t*)dat,1);
}

void LCD_WR_DATA(uint16_t dat)
{
       
        LCD_Writ_Bus(dat>>8);
        LCD_Writ_Bus(dat);

       
}
void LCD_WR_REG(uint8_t dat)
{
        DC_Clr();//Write command
        LCD_Writ_Bus(dat);
//        DMASPI0_write((uint16_t*)dat,1);
        DC_Set();//Write data
}




void DMASPI0_write(uint16_t *buf, uint16_t size)  //DMA write
{
    dma_channel_disable(DMA0,DMA_CH2);       
               
                dma_memory_address_config(DMA0,DMA_CH2,(uint32_t)buf);
                dma_transfer_number_config(DMA0,DMA_CH2,size);

                dma_channel_enable(DMA0,DMA_CH2);               

}

void DMASPI0_write_8(uint8_t *buf, uint16_t len)  //DMA write
{
       
        dma_channel_disable(DMA0,DMA_CH2);
        dma_memory_address_config(DMA0,DMA_CH2,(uint32_t)buf);
        dma_transfer_number_config(DMA0,DMA_CH2,len);
        spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
       
        //spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
       
        dma_channel_enable(DMA0, DMA_CH2);
       
  while(!dma_flag_get(DMA0,DMA_CH2, DMA_INTF_FTFIF)) {
    }
       

}

void oled_write(uint8_t dc,uint8_t sj)
{
     uint8_t sj1[1]={sj};
     if (dc==0)

     DC_Clr();
     else
     DC_Set();

    // DMASPI0_write_8(sj1,1);
}

void oled_write_16(uint16_t dat)
{
         DC_Set();
         uint16_t a=dat>>8,b=dat&0x00FF;
         uint16_t dk[2]={a,b};

         DMASPI0_write(dk,2);
}


void oled_write_8(uint8_t db)
{
   uint16_t dt[1]={db};
   DC_Set();

   DMASPI0_write(dt,1);

}

void oled_init(void)
{
  //gpio_config();
        RST_Set();
        delay_1ms(10);
        RST_Clr();
        delay_1ms(10);
        RST_Set();;
        delay_1ms(120);            

LCD_WR_REG(0x11);     

delay_1ms(120);               

LCD_WR_REG(0x36);     
LCD_WR_DATA8( 0x00);   //RGB
LCD_WR_REG(0x3A);     
LCD_WR_DATA8(0x05);   //16BIT

LCD_WR_REG(0xB2);     
LCD_WR_DATA8(0x05);   
LCD_WR_DATA8(0x05);   
LCD_WR_DATA8(0x00);   
LCD_WR_DATA8(0x33);   
LCD_WR_DATA8(0x33);   

LCD_WR_REG(0xB7);     
LCD_WR_DATA8(0x35);   


LCD_WR_REG(0xBB);     
LCD_WR_DATA8(0x21);   

LCD_WR_REG(0xC0);     
LCD_WR_DATA8(0x2C);   

LCD_WR_REG(0xC2);     
LCD_WR_DATA8(0x01);   

LCD_WR_REG(0xC3);     
LCD_WR_DATA8(0x0B);   

LCD_WR_REG(0xC4);     
LCD_WR_DATA8(0x20);   

LCD_WR_REG(0xC6);     
LCD_WR_DATA8(0x0F);   //60HZ dot inversion

LCD_WR_REG(0xD0);     
LCD_WR_DATA8(0xA7);   
LCD_WR_DATA8(0xA1);

LCD_WR_REG( 0xD0);     
LCD_WR_DATA8(0xA4);   
LCD_WR_DATA8(0xA1);   


LCD_WR_REG( 0xD6);     
LCD_WR_DATA8(0xA1);   

LCD_WR_REG(0xE0);     
LCD_WR_DATA8(0xD0);   
LCD_WR_DATA8(0x04);   
LCD_WR_DATA8(0x08);   
LCD_WR_DATA8(0x0A);   
LCD_WR_DATA8(0x09);   
LCD_WR_DATA8(0x05);   
LCD_WR_DATA8(0x2D);   
LCD_WR_DATA8(0x43);   
LCD_WR_DATA8(0x49);   
LCD_WR_DATA8(0x09);   
LCD_WR_DATA8(0x16);   
LCD_WR_DATA8(0x15);   
LCD_WR_DATA8(0x26);   
LCD_WR_DATA8(0x2B);   

LCD_WR_REG( 0xE1);     
LCD_WR_DATA8(0xD0);   
LCD_WR_DATA8(0x03);   
LCD_WR_DATA8(0x09);   
LCD_WR_DATA8(0x0A);   
LCD_WR_DATA8(0x0A);   
LCD_WR_DATA8(0x06);   
LCD_WR_DATA8(0x2E);   
LCD_WR_DATA8(0x44);   
LCD_WR_DATA8(0x40);   
LCD_WR_DATA8(0x3A);   
LCD_WR_DATA8(0x15);   
LCD_WR_DATA8(0x15);   
LCD_WR_DATA8(0x26);   
LCD_WR_DATA8(0x2A);   

LCD_WR_REG(0x21);     

LCD_WR_REG(0x29);     

delay_1ms(10);  

LCD_WR_REG(0x2A);     //Column Address Set
LCD_WR_DATA8(0x00);   
LCD_WR_DATA8(0x00);   //0
LCD_WR_DATA8(0x00);   
LCD_WR_DATA8(0xEF);   //239

LCD_WR_REG(0x2B);     //Row Address Set
LCD_WR_DATA8(0x00);   
LCD_WR_DATA8(0x00);   //0
LCD_WR_DATA8(0x01);   
LCD_WR_DATA8(0x3F);   //319

LCD_WR_REG(0x2C);  

LCD_WR_REG(0x11);
LCD_WR_REG(0x04);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
delay_1ms(120);
       
        //oled_write(Parameter,0xFF);
        //oled_write(Parameter,0xE0);
        //oled_write_16(0xFFFF);
                LCD_Clear(BLUE) ;
                LCD_Clear(RED) ;
                LCD_Clear(BLACK) ;
                LCD_Clear(WHITE) ;
                LCD_Clear(YELLOW) ;
        //oled_write(Command ,0x29);
//        oled_write_16(0x07FF);
        //oled_write(0xffff,1);
       
}

/********LCD 清屏功能********/
void LCD_Clear(uint16_t  Color)
{
        uint16_t i,j;         
        LCD_Address_Set(0,0,LCD_W-1,LCD_H-1);
    for(i=0;i<LCD_W;i++)
          {
                        for (j=0;j<LCD_H;j++)
                                {
                                        LCD_WR_DATA(Color);
                                }
          }
}

//功能描述:设置开始和结束地址
//条目数据:x1、x2 设置列的开始和结束地址
//         y1, y2 设置行的始始和结束地址

void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
     LCD_WR_REG(0x2a);     //列地址
                LCD_WR_DATA(x1+0);
                LCD_WR_DATA(x2+0);
                LCD_WR_REG(0x2b);     //行地址设定
                LCD_WR_DATA(y1+0);
                LCD_WR_DATA(y2+0);
                LCD_WR_REG(0x2c);     //写入屏幕内存

}

使用特权

评论回复
5
wangshujun| | 2023-4-21 09:56 | 只看该作者
dma完成时spi还剩下一个字节没发送,需要判定dma完成后,清除spi发送完成,再等待spi发送完成
不过除了发送显存数据的时候dma占优势,其他的时候,比如命令阶段dma更慢的

使用特权

评论回复
6
fxyc87| | 2023-4-21 10:36 | 只看该作者
片选用软件,不用内置硬件片选就好了。

使用特权

评论回复
7
优品科技|  楼主 | 2023-4-23 00:08 | 只看该作者
fxyc87 发表于 2023-4-21 10:36
片选用软件,不用内置硬件片选就好了。

是d/c,不是cs片选,这是只有一个主一个从,不用片选都可以的

使用特权

评论回复
8
优品科技|  楼主 | 2023-4-23 00:12 | 只看该作者
wangshujun 发表于 2023-4-21 09:56
dma完成时spi还剩下一个字节没发送,需要判定dma完成后,清除spi发送完成,再等待spi发送完成
不过除了发送 ...

那我这个情况要怎么处理呢?提前将所有数据存进一个数组,然后使能dma发送?还是说判断当前dna发送完成就在while循环里面去清除dc数据切换引脚的状态?现在看来初始化没有完成呢,这样的话我没法切换命令或者数据,根本完不成通讯

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

9

帖子

0

粉丝