[求助]SPI通过DMA转运到PSRAM的问题

Wi-Fi 设备、Wi-Fi 低功耗设备、Wi-Fi BLE 双模设备、Ethernet设备、Ethernet+Wi-Fi设备等
Post Reply
Gzz_lin
Posts: 8

需求:从flash芯片中读取图片数据到psram,然后发送到显示上,在读取flash和显示之间如果将数据打印出来,图片就能正常显示,否则就是花屏,以下是相关代码:

Code: Select all

STATIC VOID_T display_flash_image(UINT16_T x,UINT16_T y,UINT16_T w,UINT16_T h,UINT32_T addr)
{
    
UINT32_T image_size; image_size=w*h*2; buffer=tkl_system_psram_malloc(image_size); if(buffer==NULL) { TAL_PR_NOTICE("display psram malloc fail!"); return; } tal_mutex_lock(gx_dis_mutex); hly_flash_read(addr,buffer,image_size); // for(UINT32_T i=0;i<153600;i++) // { // TAL_PR_NOTICE("***buufer %06X:%02X",i,*(buffer+i)); // } screen_draw_image(x,y,w,h,buffer); tal_mutex_unlock(gx_dis_mutex); tkl_system_free(buffer); buffer=NULL; }

SPI部分使用了DMA,并且移除了官方关于CS引脚的相关代码

Code: Select all

#define SPI_ID          TUYA_SPI_NUM_0           // SPI ID
STATIC QUEUE_HANDLE gx_spi_queue_handle;        //spi消息队列

/*spi init*/
CONST TUYA_SPI_BASE_CFG_T GX_SPI_CFG = {
    .mode = TUYA_SPI_MODE3,
    .freq_hz = SPI_FREQ,
    .databits = TUYA_SPI_DATA_BIT8,
    .bitorder = TUYA_SPI_ORDER_MSB2LSB,
    .role = TUYA_SPI_ROLE_MASTER,
    .type = TUYA_SPI_SOFT_TYPE,//TUYA_SPI_AUTO_TYPE,//
    .spi_dma_flags=0
};

STATIC VOID_T spi_irq_cb(TUYA_SPI_NUM_E port, TUYA_SPI_IRQ_EVT_E event)
{
    UINT8_T e;
   //TAL_PR_DEBUG("spi irq=%d",(UINT8_T)TUYA_SPI_EVENT_RX_COMPLETE);
    if(port==SPI_ID&&event==TUYA_SPI_EVENT_RX_COMPLETE)
    {
        e=2;
        tal_queue_post(gx_spi_queue_handle,&e,100);
    }

}
OPERATE_RET hly_spi_init(VOID_T)
{
    OPERATE_RET rt = OPRT_OK;
    tal_queue_create_init(&gx_spi_queue_handle,sizeof(UINT8_T),1);
    tkl_spi_irq_init(SPI_ID,spi_irq_cb);
    tkl_spi_irq_enable(SPI_ID);
    rt = tkl_spi_init(SPI_ID, &GX_SPI_CFG);
    return rt;

}
OPERATE_RET hly_spi_write_byte(UINT8_T data)
{
    OPERATE_RET rt;
    TUYA_SPI_IRQ_EVT_E tmp;
    tal_queue_fetch(gx_spi_queue_handle,&tmp,300);
    rt=tkl_spi_send(SPI_ID, &data, 1);
    //TAL_PR_DEBUG("spi send:%d   rt=%d",data,rt);
    return rt;
}

OPERATE_RET hly_spi_write_buffer(UINT8_T* data,UINT32_T len)
{
    TUYA_SPI_IRQ_EVT_E tmp;
    tal_queue_fetch(gx_spi_queue_handle,&tmp,300);
    while(len>0)
    {
        if(len>=1024)
        {
            tkl_spi_send(SPI_ID, data, 1024);
            len-=1024;
            data+=1024;
        }
        else
        {
            tkl_spi_send(SPI_ID, data, len);
            len-=len;
        }
        
if(tal_queue_fetch(gx_spi_queue_handle,&tmp,300)!=OPRT_OK) { return OPRT_COM_ERROR; } } return OPRT_OK; } UINT8_T hly_spi_read_btye() { UINT8_T data; tkl_spi_recv(SPI_ID,&data,1); return data; } OPERATE_RET hly_spi_read_buffer(UINT8_T* buffer,UINT32_T len) { while(len) { if(len>=1024) { tkl_spi_recv(SPI_ID,buffer,1024); len-=1024; buffer+=1024; } else { tkl_spi_recv(SPI_ID,buffer,len); len-=len; buffer+=len; } } return OPRT_OK; }

屏幕显示相关函数

Code: Select all

#define SCREEN_CS_PIN   TUYA_GPIO_NUM_18  // CS引脚
#define SCREEN_RES_PIN  TUYA_GPIO_NUM_47 // RES引脚
#define SCREEN_DC_PIN   TUYA_GPIO_NUM_46  // DC引脚
#define SCREEN_BL_PIN   TUYA_GPIO_NUM_19  // 背光

#define SCREEN_CS_H() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_CS_PIN)*4)) = GPIO_OUTPUT_HIGH; \
} while(0)
#define SCREEN_CS_L() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_CS_PIN)*4)) = GPIO_OUTPUT_LOW; \
} while(0)

// #define SCREEN_CS_H do{}while(0)
// #define SCREEN_CS_L do{}while(0)
#define SCREEN_RES_H() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_RES_PIN)*4)) = GPIO_OUTPUT_HIGH; \
} while(0)
#define SCREEN_RES_L() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_RES_PIN)*4)) = GPIO_OUTPUT_LOW; \
} while(0)
#define SCREEN_DC_H() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_DC_PIN)*4)) = GPIO_OUTPUT_HIGH; \
} while(0)
#define SCREEN_DC_L() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_DC_PIN)*4)) = GPIO_OUTPUT_LOW; \
} while(0)

#define SCREEN_BL_H() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_BL_PIN)*4)) = GPIO_OUTPUT_HIGH; \
} while(0)
#define SCREEN_BL_L() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(SCREEN_BL_PIN)*4)) = GPIO_OUTPUT_LOW; \
} while(0)


// #define SCREEN_RAM_SIZE 1024

// UINT16_T gb_screen_rom[SCREEN_RAM_SIZE];
CONST TUYA_GPIO_BASE_CFG_T GX_GPIO_CFG = 
{
    .mode = TUYA_GPIO_OPENDRAIN_PULLUP,
    .direct = TUYA_GPIO_OUTPUT,
    .level = TUYA_GPIO_LEVEL_HIGH
};
STATIC VOID_T screen_cmd(UINT8_T cmd)
{
    SCREEN_DC_L();
    SCREEN_CS_L();
    hly_spi_write_byte(cmd);
    SCREEN_CS_H();
}

STATIC VOID_T screen_data8(UINT8_T dat)
{
    SCREEN_DC_H();
    SCREEN_CS_L();
    hly_spi_write_byte(dat);
    SCREEN_CS_H();
}

STATIC VOID_T screen_data16(UINT16_T dat)
{
    SCREEN_DC_H();
    SCREEN_CS_L();
        hly_spi_write_byte(dat>>8);
        hly_spi_write_byte(dat);
    SCREEN_CS_H();
}

STATIC VOID screen_set_rectangle(UINT16_T x0, UINT16_T y0, UINT16_T x1, UINT16_T y1)
{
    screen_cmd(0x2A);
    screen_data16(x0);
    screen_data16(x1);

screen_cmd(0x2B);
screen_data16(y0);
screen_data16(y1);

screen_cmd(0x2C);
}

OPERATE_RET screen_init(VOID_T)
{

tkl_gpio_init(SCREEN_CS_PIN, &GX_GPIO_CFG);
tkl_gpio_init(SCREEN_DC_PIN, &GX_GPIO_CFG);
tkl_gpio_init(SCREEN_RES_PIN, &GX_GPIO_CFG);

SCREEN_CS_H();
SCREEN_BL_L();
SCREEN_RES_L();
tal_system_sleep(100);
SCREEN_RES_H();
tal_system_sleep(100); // ms
screen_cmd(0x11);
tal_system_sleep(100); // ms

screen_cmd(0x36);
screen_data8(0x70);

screen_cmd(0x3A);
screen_data8(0x05); //    262Kɫ 06

screen_cmd(0xB2);
screen_data8(0x0C);
screen_data8(0x0C);
screen_data8(0x00);
screen_data8(0x33);
screen_data8(0x33);

screen_cmd(0xB7);
screen_data8(0x75); // VGH=14.97V, VGL=-10.43V

screen_cmd(0xBB); // VCOM
screen_data8(0x21);

screen_cmd(0xC0);
screen_data8(0x2C);

screen_cmd(0xC2);
screen_data8(0x01);

screen_cmd(0xC3); // GVDD
screen_data8(0x13);

screen_cmd(0xC4);
screen_data8(0x20);

screen_cmd(0xC6);
screen_data8(0x0F);

screen_cmd(0xD0);
screen_data8(0xA4);
screen_data8(0xA1);

screen_cmd(0xd6);
screen_data8(0xa1);

screen_cmd(0xE0);
screen_data8(0x70);
screen_data8(0x04);
screen_data8(0x0A);
screen_data8(0x08);
screen_data8(0x07);
screen_data8(0x05);
screen_data8(0x32);
screen_data8(0x32);
screen_data8(0x48);
screen_data8(0x38);
screen_data8(0x15);
screen_data8(0x15);
screen_data8(0x2A);
screen_data8(0x2E);

screen_cmd(0xE1);
screen_data8(0x70);
screen_data8(0x07);
screen_data8(0x0D);
screen_data8(0x09);
screen_data8(0x09);
screen_data8(0x16);
screen_data8(0x30);
screen_data8(0x44);
screen_data8(0x49);
screen_data8(0x39);
screen_data8(0x16);
screen_data8(0x16);
screen_data8(0x2B);
screen_data8(0x2F);

screen_cmd(0x21);

screen_cmd(0x29);
// screen_fill(0,0,320,240,0x0000);
TAL_PR_DEBUG("---------------screen init done----------.");
SCREEN_BL_H();

return 0;
}
OPERATE_RET screen_fill(UINT16_T x,UINT16_T y,UINT16_T w,UINT16_T h,UINT16_T color)
{
    UINT32_T i;
    UINT32_T count;
    
count=w*h; screen_set_rectangle(x,y,x+w-1,y+h-1); SCREEN_DC_H(); SCREEN_CS_L(); // while(count) // { // if(count>SCREEN_RAM_SIZE) // { // for(i=0;i<SCREEN_RAM_SIZE;i++) // { // gb_screen_rom[i]=color; // } // hly_spi_write_buffer(&gb_screen_rom,SCREEN_RAM_SIZE*2); // count-=SCREEN_RAM_SIZE; // } // else // { // for(i=0;i<count;i++) // { // gb_screen_rom[i]=color; // } // hly_spi_write_buffer(&gb_screen_rom,count*2); // count-=count; // } // } //SCREEN_RAM_SIZE //count=10; for(i=0;i<count;i++) { hly_spi_write_byte(color>>8); hly_spi_write_byte(color); } SCREEN_CS_H(); } OPERATE_RET screen_draw_image(UINT16_T x,UINT16_T y,UINT16_T w,UINT16_T h,UINT8_T* image) { UINT32_T count; count=w*h*2; screen_set_rectangle(x,y,x+w-1,y+h-1); SCREEN_DC_H(); SCREEN_CS_L(); hly_spi_write_buffer(image,count); SCREEN_CS_H(); }

FLASH操作相关函数

Code: Select all

#define FLASH_CS_PIN    TUYA_GPIO_NUM_15
#define FLASH_CS_H() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(FLASH_CS_PIN)*4)) = GPIO_OUTPUT_HIGH; \
} while(0)
#define FLASH_CS_L() do { \
    *((volatile unsigned long *) (SOC_AON_GPIO_REG_BASE+(FLASH_CS_PIN)*4)) = GPIO_OUTPUT_LOW; \
} while(0)

CONST TUYA_GPIO_BASE_CFG_T GX_FLASH_GPIO_CFG = 
{
    .mode = TUYA_GPIO_OPENDRAIN_PULLUP,
    .direct = TUYA_GPIO_OUTPUT,
    .level = TUYA_GPIO_LEVEL_HIGH
};

OPERATE_RET hly_flash_init()
{    
OPERATE_RET rt; rt=tkl_gpio_init(FLASH_CS_PIN, &GX_FLASH_GPIO_CFG); FLASH_CS_H() ; return rt; } // 等待25Q64空闲 STATIC OPERATE_RET hly_flash_idle() { UINT16_T t=0; unsigned char status; do { // t++; // if (t>1000) // { // return -1; // }
FLASH_CS_L(); hly_spi_write_byte(0x05); // 读状态寄存器命令 status = hly_spi_read_btye(); FLASH_CS_H(); } while (status & 0x01); // 忙标志位 return 0; } STATIC OPERATE_RET hly_flash_page_program(UINT32_T addr,UINT8_T* databuffer,UINT32_T len) { OPERATE_RET rt; FLASH_CS_L(); hly_spi_write_byte(0x06); //写使能 FLASH_CS_H(); FLASH_CS_L(); hly_spi_write_byte(0x02); //页编程 hly_spi_write_byte((addr>>16)&0xFF); hly_spi_write_byte((addr>>8)&0xFF); hly_spi_write_byte((addr&0xFF)); rt=hly_spi_write_buffer(databuffer,len); FLASH_CS_H(); if(rt=0) { rt=hly_flash_idle(); }
return rt; } OPERATE_RET hly_flash_write(UINT32_T addr,UINT8_T* databuffer,UINT32_T len) { OPERATE_RET rt; UINT32_T bytesWritten = 0; while (len > 0) { UINT32_T bytesToWrite = (len > 256) ? 256 : len; rt=hly_flash_page_program(addr + bytesWritten, databuffer + bytesWritten, bytesToWrite); bytesWritten += bytesToWrite; len -= bytesToWrite; } return rt; } OPERATE_RET hly_flash_read(UINT32_T addr,UINT8_T* databuffer,UINT32_T len) { OPERATE_RET rt; FLASH_CS_L(); hly_spi_write_byte(0x0B); //快速读取 hly_spi_write_byte((addr>>16)&0xFF); hly_spi_write_byte((addr>>8)&0xFF); hly_spi_write_byte((addr&0xFF)); rt=hly_spi_read_buffer(databuffer,len); FLASH_CS_H(); return rt; } OPERATE_RET hly_flash_full_erase() { OPERATE_RET rt; FLASH_CS_L(); hly_spi_write_byte(0x06); //写使能 FLASH_CS_H(); FLASH_CS_L(); hly_spi_write_byte(0xC7); //全部擦除 FLASH_CS_H(); rt=hly_flash_idle(); return rt; }
Gzz_lin
Posts: 8

Re: [求助]SPI通过DMA转运到PSRAM的问题

经过测试,使用tkl_spi_recv之后sclk引脚就一直发时钟不会停止了,有可能是我删除了SPI CS引脚的原因,也有可能是本身底层代码的问题,把CS引脚强行绑定也不知道为什么,这样的话SPI就只能一对一通信了.

Post Reply