Работаем с дисплеем ILI9341 по DMA

Опубликовано lamazavr - вс, 12/28/2014 - 16:07
Body

Я уже писал о работе с дисплеем ILI9341.
Частота обновления экрана при этом оставляла желать лучшего. Даже после игр с частотой SPI ничего приемлемого добиться не удалось. На этой почве бросил это дело на пол пути. А недавно увидел вот такое:

Т.е. возможно и кино крутить на этом дисплее.
Сразу подумалось о DMA. Быстренько набросал такое:

u32 pixels_left = 0;
u8* p_buffer;

void spi1_init_dma(u8* buffer,u32 count)
{
    DMA_InitTypeDef  DMA_InitStructure;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
 
    /* Deinitialize DMA Streams */
    DMA_DeInit(DMA2_Stream3); //SPI1_TX_DMA_STREAM

    if (count > MAX_DMA_REQUEST)
    {
        pixels_left = count - MAX_DMA_REQUEST;
        count = MAX_DMA_REQUEST;
    } else {
        pixels_left = 0;
    }
    
    //tx       
    DMA_InitStructure.DMA_Channel = DMA_Channel_3;  
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(SPI1->DR);
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)buffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
    DMA_InitStructure.DMA_BufferSize = (uint32_t)(count);
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         
    DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
    DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
    DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
    DMA_Init(DMA2_Stream3, &DMA_InitStructure);

    NVIC_EnableIRQ(DMA2_Stream3_IRQn);
    
    /* Разрешаем прерывание по окончанию передачи данных */
    DMA_ITConfig(DMA2_Stream3, DMA_IT_TC, ENABLE);

    SPI_I2S_DMACmd(SPI1, SPI_I2S_DMAReq_Tx, ENABLE);
}

void start_dma(u8* buffer,u32 count)
{
    spi_transfer = 1;
    TFT_DC_SET;
    TFT_CS_RESET;
    p_buffer = buffer;
    
    spi1_init_dma(p_buffer, count);
    
    /* Включаем DMA */
    DMA_Cmd(DMA2_Stream3, ENABLE);
}

Тут есть тонкий момент. Несмотря на то, что поле BufferSize в структуре имеет 32 бита, на самом деле DMA умеет передавать только 65535 байт. А нам нужно передать 320*240*2, что несколько больше. Пришлось разбить на несколько тразакций.

//tx
void DMA2_Stream3_IRQHandler()
{
    /* Проверяем наше ли это прерывание ;) */
    if(DMA_GetITStatus(DMA2_Stream3, DMA_IT_TCIF3))
    {
        spi_transfer = 0;
        if (pixels_left)
        {
            p_buffer+=MAX_DMA_REQUEST;
            spi1_init_dma(p_buffer, pixels_left);
            spi_transfer = 1;
            DMA_Cmd(DMA2_Stream3, ENABLE);
        } else {
            TFT_CS_SET;
        }
        /* Очищаем бит обработки прерывания */
        DMA_ClearITPendingBit(DMA2_Stream3, DMA_IT_TCIF3);  
    } 
}

Скорость увеличилась в разы. Но все равно заметно обновление кадра. Но при обновлении части экрана должно работать отлично.

PS обнаружилась проблема. GIMP экспортирует картинку в массив. Только вот слать нужно меняя байты местами. Как это сделать с DMA пока не придумал ;(

PPS Испытал дисплей со своей малиной

Комментарии

Пытаюсь тоже побороть тормазнутость этого дисплея, с дма натолкнулся на грабли что нужно программно дёргать DC и CS, поэтому начал делать на прерываниях SPI, но всё равно не то пальто.
Можешь поделится проектом? ну пожааааааалуйста

Добавить комментарий

Этот вопрос задается для того, чтобы выяснить, являетесь ли Вы человеком или представляете из себя автоматическую спам-рассылку.