kopia lustrzana https://github.com/OpenRTX/OpenRTX
519 wiersze
17 KiB
C
519 wiersze
17 KiB
C
|
/***************************************************************************
|
||
|
* Copyright (C) 2020 by Silvano Seva IU2KWO and Niccolò Izzo IU2KIN *
|
||
|
* *
|
||
|
* This program is free software; you can redistribute it and/or modify *
|
||
|
* it under the terms of the GNU General Public License as published by *
|
||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||
|
* (at your option) any later version. *
|
||
|
* *
|
||
|
* This program is distributed in the hope that it will be useful, *
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||
|
* GNU General Public License for more details. *
|
||
|
* *
|
||
|
* You should have received a copy of the GNU General Public License *
|
||
|
* along with this program; if not, see <http://www.gnu.org/licenses/> *
|
||
|
***************************************************************************/
|
||
|
|
||
|
#include <interfaces/gpio.h>
|
||
|
#include <interfaces/display.h>
|
||
|
#include <interfaces/delays.h>
|
||
|
#include <interfaces/platform.h>
|
||
|
#include <hwconfig.h>
|
||
|
#include <string.h>
|
||
|
#include <os.h>
|
||
|
|
||
|
/**
|
||
|
* LCD command set, basic and extended
|
||
|
*/
|
||
|
|
||
|
#define CMD_NOP 0x00 // No Operation
|
||
|
#define CMD_SWRESET 0x01 // Software reset
|
||
|
#define CMD_RDDIDIF 0x04 // Read Display ID Info
|
||
|
#define CMD_RDDST 0x09 // Read Display Status
|
||
|
#define CMD_RDDPM 0x0a // Read Display Power
|
||
|
#define CMD_RDD_MADCTL 0x0b // Read Display
|
||
|
#define CMD_RDD_COLMOD 0x0c // Read Display Pixel
|
||
|
#define CMD_RDDDIM 0x0d // Read Display Image
|
||
|
#define CMD_RDDSM 0x0e // Read Display Signal
|
||
|
#define CMD_RDDSDR 0x0f // Read display self-diagnostic resut
|
||
|
#define CMD_SLPIN 0x10 // Sleep in & booster off
|
||
|
#define CMD_SLPOUT 0x11 // Sleep out & booster on
|
||
|
#define CMD_PTLON 0x12 // Partial mode on
|
||
|
#define CMD_NORON 0x13 // Partial off (Normal)
|
||
|
#define CMD_INVOFF 0x20 // Display inversion off
|
||
|
#define CMD_INVON 0x21 // Display inversion on
|
||
|
#define CMD_GAMSET 0x26 // Gamma curve select
|
||
|
#define CMD_DISPOFF 0x28 // Display off
|
||
|
#define CMD_DISPON 0x29 // Display on
|
||
|
#define CMD_CASET 0x2a // Column address set
|
||
|
#define CMD_RASET 0x2b // Row address set
|
||
|
#define CMD_RAMWR 0x2c // Memory write
|
||
|
#define CMD_RGBSET 0x2d // LUT parameter (16-to-18 color mapping)
|
||
|
#define CMD_RAMRD 0x2e // Memory read
|
||
|
#define CMD_PTLAR 0x30 // Partial start/end address set
|
||
|
#define CMD_VSCRDEF 0x31 // Vertical Scrolling Direction
|
||
|
#define CMD_TEOFF 0x34 // Tearing effect line off
|
||
|
#define CMD_TEON 0x35 // Tearing effect mode set & on
|
||
|
#define CMD_MADCTL 0x36 // Memory data access control
|
||
|
#define CMD_VSCRSADD 0x37 // Vertical scrolling start address
|
||
|
#define CMD_IDMOFF 0x38 // Idle mode off
|
||
|
#define CMD_IDMON 0x39 // Idle mode on
|
||
|
#define CMD_COLMOD 0x3a // Interface pixel format
|
||
|
#define CMD_RDID1 0xda // Read ID1
|
||
|
#define CMD_RDID2 0xdb // Read ID2
|
||
|
#define CMD_RDID3 0xdc // Read ID3
|
||
|
|
||
|
#define CMD_SETOSC 0xb0 // Set internal oscillator
|
||
|
#define CMD_SETPWCTR 0xb1 // Set power control
|
||
|
#define CMD_SETDISPLAY 0xb2 // Set display control
|
||
|
#define CMD_SETCYC 0xb4 // Set display cycle
|
||
|
#define CMD_SETBGP 0xb5 // Set BGP voltage
|
||
|
#define CMD_SETVCOM 0xb6 // Set VCOM voltage
|
||
|
#define CMD_SETEXTC 0xb9 // Enter extension command
|
||
|
#define CMD_SETOTP 0xbb // Set OTP
|
||
|
#define CMD_SETSTBA 0xc0 // Set Source option
|
||
|
#define CMD_SETID 0xc3 // Set ID
|
||
|
#define CMD_SETPANEL 0xcc // Set Panel characteristics
|
||
|
#define CMD_GETHID 0xd0 // Read Himax internal ID
|
||
|
#define CMD_SETGAMMA 0xe0 // Set Gamma
|
||
|
#define CMD_SET_SPI_RDEN 0xfe // Set SPI Read address (and enable)
|
||
|
#define CMD_GET_SPI_RDEN 0xff // Get FE A[7:0] parameter
|
||
|
|
||
|
/* Addresses for memory-mapped display data and command (through FSMC) */
|
||
|
#define LCD_FSMC_ADDR_COMMAND 0x60000000
|
||
|
#define LCD_FSMC_ADDR_DATA 0x60040000
|
||
|
|
||
|
/*
|
||
|
* LCD framebuffer, statically allocated.
|
||
|
* Pixel format is RGB565, 16 bit per pixel
|
||
|
*/
|
||
|
static uint16_t frameBuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
|
||
|
OS_FLAG_GRP renderCompleted;
|
||
|
OS_ERR err;
|
||
|
|
||
|
void __attribute__((used)) DMA2_Stream7_IRQHandler()
|
||
|
{
|
||
|
OSIntEnter();
|
||
|
DMA2->HIFCR |= DMA_HIFCR_CTCIF7 | DMA_HIFCR_CTEIF7; /* Clear flags */
|
||
|
gpio_setPin(LCD_CS);
|
||
|
OSFlagPost(&renderCompleted, 0x01, OS_OPT_POST_FLAG_SET, &err);
|
||
|
OSIntExit();
|
||
|
}
|
||
|
|
||
|
static inline __attribute__((__always_inline__)) void writeCmd(uint8_t cmd)
|
||
|
{
|
||
|
*((volatile uint8_t*) LCD_FSMC_ADDR_COMMAND) = cmd;
|
||
|
}
|
||
|
|
||
|
static inline __attribute__((__always_inline__)) void writeData(uint8_t val)
|
||
|
{
|
||
|
*((volatile uint8_t*) LCD_FSMC_ADDR_DATA) = val;
|
||
|
}
|
||
|
|
||
|
void display_init()
|
||
|
{
|
||
|
/* Create flag for render completion wait */
|
||
|
OSFlagCreate(&renderCompleted, "", 0, &err);
|
||
|
|
||
|
/* Clear framebuffer, setting all pixels to 0xFFFF makes the screen white */
|
||
|
memset(frameBuffer, 0xFF, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(uint16_t));
|
||
|
|
||
|
/*
|
||
|
* Turn on DMA2 and configure its interrupt. DMA is used to transfer the
|
||
|
* framebuffer content to the screen without using CPU.
|
||
|
*/
|
||
|
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
|
||
|
__DSB();
|
||
|
|
||
|
NVIC_ClearPendingIRQ(DMA2_Stream7_IRQn);
|
||
|
NVIC_SetPriority(DMA2_Stream7_IRQn, 14);
|
||
|
NVIC_EnableIRQ(DMA2_Stream7_IRQn);
|
||
|
|
||
|
/*
|
||
|
* Turn on FSMC, used to efficiently manage the display data and control
|
||
|
* lines.
|
||
|
*/
|
||
|
RCC->AHB3ENR |= RCC_AHB3ENR_FSMCEN;
|
||
|
__DSB();
|
||
|
|
||
|
/* Configure FSMC as LCD driver.
|
||
|
* BCR1 config:
|
||
|
* - CBURSTRW = 0: asynchronous write operation
|
||
|
* - ASYNCWAIT = 0: NWAIT not taken into account when running asynchronous protocol
|
||
|
* - EXTMOD = 0: do not take into account values of BWTR register
|
||
|
* - WAITEN = 0: nwait signal disabled
|
||
|
* - WREN = 1: write operations enabled
|
||
|
* - WAITCFG = 0: nwait active one data cycle before wait state
|
||
|
* - WRAPMOD = 0: direct wrapped burst disabled
|
||
|
* - WAITPOL = 0: nwait active low
|
||
|
* - BURSTEN = 0: burst mode disabled
|
||
|
* - FACCEN = 1: NOR flash memory disabled
|
||
|
* - MWID = 1: 16 bit external memory device
|
||
|
* - MTYP = 2: NOR
|
||
|
* - MUXEN = 0: addr/data not multiplexed
|
||
|
* - MBNEN = 1: enable bank
|
||
|
*/
|
||
|
FSMC_Bank1->BTCR[0] = 0x10D9;
|
||
|
|
||
|
/* BTR1 config:
|
||
|
* - ACCMOD = 0: access mode A
|
||
|
* - DATLAT = 0: don't care in asynchronous mode
|
||
|
* - CLKDIV = 1: don't care in asynchronous mode, 0000 is reserved
|
||
|
* - BUSTURN = 0: time between two consecutive write accesses
|
||
|
* - DATAST = 5: we must have LCD twrl < DATAST*HCLK_period
|
||
|
* - ADDHLD = 1: used only in mode D, 0000 is reserved
|
||
|
* - ADDSET = 7: address setup time 7*HCLK_period
|
||
|
*/
|
||
|
FSMC_Bank1->BTCR[1] = (0 << 28) /* ACCMOD */
|
||
|
| (0 << 24) /* DATLAT */
|
||
|
| (1 << 20) /* CLKDIV */
|
||
|
| (0 << 16) /* BUSTURN */
|
||
|
| (5 << 8) /* DATAST */
|
||
|
| (1 << 4) /* ADDHLD */
|
||
|
| 7; /* ADDSET */
|
||
|
|
||
|
/* Configure alternate function for data and control lines. */
|
||
|
gpio_setMode(LCD_D0, ALTERNATE);
|
||
|
gpio_setMode(LCD_D1, ALTERNATE);
|
||
|
gpio_setMode(LCD_D2, ALTERNATE);
|
||
|
gpio_setMode(LCD_D3, ALTERNATE);
|
||
|
gpio_setMode(LCD_D4, ALTERNATE);
|
||
|
gpio_setMode(LCD_D5, ALTERNATE);
|
||
|
gpio_setMode(LCD_D6, ALTERNATE);
|
||
|
gpio_setMode(LCD_D7, ALTERNATE);
|
||
|
gpio_setMode(LCD_RS, ALTERNATE);
|
||
|
gpio_setMode(LCD_WR, ALTERNATE);
|
||
|
gpio_setMode(LCD_RD, ALTERNATE);
|
||
|
|
||
|
gpio_setAlternateFunction(LCD_D0, 12);
|
||
|
gpio_setAlternateFunction(LCD_D1, 12);
|
||
|
gpio_setAlternateFunction(LCD_D2, 12);
|
||
|
gpio_setAlternateFunction(LCD_D3, 12);
|
||
|
gpio_setAlternateFunction(LCD_D4, 12);
|
||
|
gpio_setAlternateFunction(LCD_D5, 12);
|
||
|
gpio_setAlternateFunction(LCD_D6, 12);
|
||
|
gpio_setAlternateFunction(LCD_D7, 12);
|
||
|
gpio_setAlternateFunction(LCD_RS, 12);
|
||
|
gpio_setAlternateFunction(LCD_WR, 12);
|
||
|
gpio_setAlternateFunction(LCD_RD, 12);
|
||
|
|
||
|
/* Reset and chip select lines as outputs */
|
||
|
gpio_setMode(LCD_CS, OUTPUT);
|
||
|
gpio_setMode(LCD_RST, OUTPUT);
|
||
|
|
||
|
gpio_setPin(LCD_CS); /* CS idle state is high level */
|
||
|
gpio_clearPin(LCD_RST); /* Put LCD in reset mode */
|
||
|
|
||
|
delayMs(20);
|
||
|
gpio_setPin(LCD_RST); /* Exit from reset */
|
||
|
|
||
|
gpio_clearPin(LCD_CS);
|
||
|
|
||
|
/**
|
||
|
* The command sequence below has been taken as-is from the LCD initialisation
|
||
|
* routine at address 0x0804d1c8 of Tytera's firmware for MD-UV380 radios,
|
||
|
* version S18.016.
|
||
|
* It has also been cross-checked with the firmware image for MD-380/390 to
|
||
|
* ensure that is compatible also with the displays of that radios.
|
||
|
* Without this sequence, screen needs framebuffer data to be sent very slowly,
|
||
|
* otherwise nothing will be rendered.
|
||
|
* Since we do not have the datasheet for the controller employed in this
|
||
|
* screen, we can only do copy-and-paste...
|
||
|
*/
|
||
|
uint8_t lcd_type = platform_getHwInfo()->lcd_type;
|
||
|
|
||
|
if((lcd_type == 2) || (lcd_type == 3))
|
||
|
{
|
||
|
writeCmd(0xfe);
|
||
|
writeCmd(0xef);
|
||
|
writeCmd(0xb4);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xff);
|
||
|
writeData(0x16);
|
||
|
writeCmd(0xfd);
|
||
|
|
||
|
if(lcd_type == 3)
|
||
|
writeData(0x40);
|
||
|
else
|
||
|
writeData(0x4f);
|
||
|
|
||
|
writeCmd(0xa4);
|
||
|
writeData(0x70);
|
||
|
writeCmd(0xe7);
|
||
|
writeData(0x94);
|
||
|
writeData(0x88);
|
||
|
writeCmd(0xea);
|
||
|
writeData(0x3a);
|
||
|
writeCmd(0xed);
|
||
|
writeData(0x11);
|
||
|
writeCmd(0xe4);
|
||
|
writeData(0xc5);
|
||
|
writeCmd(0xe2);
|
||
|
writeData(0x80);
|
||
|
writeCmd(0xa3);
|
||
|
writeData(0x12);
|
||
|
writeCmd(0xe3);
|
||
|
writeData(0x07);
|
||
|
writeCmd(0xe5);
|
||
|
writeData(0x10);
|
||
|
writeCmd(0xf0);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xf1);
|
||
|
writeData(0x55);
|
||
|
writeCmd(0xf2);
|
||
|
writeData(0x05);
|
||
|
writeCmd(0xf3);
|
||
|
writeData(0x53);
|
||
|
writeCmd(0xf4);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xf5);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xf7);
|
||
|
writeData(0x27);
|
||
|
writeCmd(0xf8);
|
||
|
writeData(0x22);
|
||
|
writeCmd(0xf9);
|
||
|
writeData(0x77);
|
||
|
writeCmd(0xfa);
|
||
|
writeData(0x35);
|
||
|
writeCmd(0xfb);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xfc);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xfe);
|
||
|
writeCmd(0xef);
|
||
|
writeCmd(0xe9);
|
||
|
writeData(0x00);
|
||
|
delayMs(20);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
writeCmd(0x11);
|
||
|
delayMs(120);
|
||
|
writeCmd(0xb1);
|
||
|
writeData(0x05);
|
||
|
writeData(0x3c);
|
||
|
writeData(0x3c);
|
||
|
writeCmd(0xb2);
|
||
|
writeData(0x05);
|
||
|
writeData(0x3c);
|
||
|
writeData(0x3c);
|
||
|
writeCmd(0xb3);
|
||
|
writeData(0x05);
|
||
|
writeData(0x3c);
|
||
|
writeData(0x3c);
|
||
|
writeData(0x05);
|
||
|
writeData(0x3c);
|
||
|
writeData(0x3c);
|
||
|
writeCmd(0xb4);
|
||
|
writeData(0x03);
|
||
|
writeCmd(0xc0);
|
||
|
writeData(0x28);
|
||
|
writeData(0x08);
|
||
|
writeData(0x04);
|
||
|
writeCmd(0xc1);
|
||
|
writeData(0xc0);
|
||
|
writeCmd(0xc2);
|
||
|
writeData(0xd);
|
||
|
writeData(0x00);
|
||
|
writeCmd(0xc3);
|
||
|
writeData(0x8d);
|
||
|
writeData(0x2a);
|
||
|
writeCmd(0xc4);
|
||
|
writeData(0x8d);
|
||
|
writeData(0xee);
|
||
|
writeCmd(0xc5);
|
||
|
writeData(0x1a);
|
||
|
writeCmd(0x36);
|
||
|
writeData(0x08);
|
||
|
writeCmd(0xe0);
|
||
|
writeData(0x04);
|
||
|
writeData(0x0c);
|
||
|
writeData(0x07);
|
||
|
writeData(0x0a);
|
||
|
writeData(0x2e);
|
||
|
writeData(0x30);
|
||
|
writeData(0x25);
|
||
|
writeData(0x2a);
|
||
|
writeData(0x28);
|
||
|
writeData(0x26);
|
||
|
writeData(0x2e);
|
||
|
writeData(0x3a);
|
||
|
writeData(0x00);
|
||
|
writeData(0x01);
|
||
|
writeData(0x03);
|
||
|
writeData(0x13);
|
||
|
writeCmd(0xe1);
|
||
|
writeData(0x04);
|
||
|
writeData(0x16);
|
||
|
writeData(0x06);
|
||
|
writeData(0x0d);
|
||
|
writeData(0x2d);
|
||
|
writeData(0x26);
|
||
|
writeData(0x23);
|
||
|
writeData(0x27);
|
||
|
writeData(0x27);
|
||
|
writeData(0x25);
|
||
|
writeData(0x2d);
|
||
|
writeData(0x3b);
|
||
|
writeData(0x00);
|
||
|
writeData(0x01);
|
||
|
writeData(0x04);
|
||
|
writeData(0x13);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Configuring screen's memory access control: TYT MD3x0 radios have the screen
|
||
|
* rotated by 90° degrees, so we have to exchange row and coloumn indexing.
|
||
|
* Moreover, we need to invert the vertical updating order to avoid painting
|
||
|
* an image from bottom to top (that is, horizontally mirrored).
|
||
|
* For reference see, in HX8353-E datasheet, MADCTL description at page 149
|
||
|
* and paragraph 6.2.1, starting at page 48.
|
||
|
*
|
||
|
* Current confguration:
|
||
|
* - MY (bit 7): 0 -> do not invert y direction
|
||
|
* - MX (bit 6): 1 -> invert x direction
|
||
|
* - MV (bit 5): 1 -> exchange x and y
|
||
|
* - ML (bit 4): 0 -> refresh screen top-to-bottom
|
||
|
* - BGR (bit 3): 0 -> RGB pixel format
|
||
|
* - SS (bit 2): 0 -> refresh screen left-to-right
|
||
|
* - bit 1 and 0: don't care
|
||
|
*/
|
||
|
|
||
|
writeCmd(CMD_MADCTL);
|
||
|
if(lcd_type == 1)
|
||
|
{
|
||
|
writeData(0x60); /* Reference case: MD-390(G) */
|
||
|
}
|
||
|
else if(lcd_type == 2)
|
||
|
{
|
||
|
writeData(0x20); /* Reference case: MD-380V(G) */
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
writeData(0xA0); /* Reference case: MD-380 */
|
||
|
}
|
||
|
|
||
|
writeCmd(CMD_CASET);
|
||
|
writeData(0x00);
|
||
|
writeData(0x00);
|
||
|
writeData(0x00);
|
||
|
writeData(0xA0); /* 160 coloumns */
|
||
|
writeCmd(CMD_RASET);
|
||
|
writeData(0x00);
|
||
|
writeData(0x00);
|
||
|
writeData(0x00);
|
||
|
writeData(0x80); /* 128 rows */
|
||
|
writeCmd(CMD_COLMOD);
|
||
|
writeData(0x05); /* 16 bit per pixel */
|
||
|
delayMs(10);
|
||
|
|
||
|
writeCmd(CMD_SLPOUT); /* Finally, turn on display */
|
||
|
delayMs(120);
|
||
|
writeCmd(CMD_DISPON);
|
||
|
writeCmd(CMD_RAMWR);
|
||
|
|
||
|
gpio_setPin(LCD_CS);
|
||
|
}
|
||
|
|
||
|
void display_terminate()
|
||
|
{
|
||
|
OSFlagDel(&renderCompleted, OS_OPT_DEL_NO_PEND, &err);
|
||
|
|
||
|
/* Shut off FSMC and deallocate framebuffer */
|
||
|
RCC->AHB3ENR &= ~RCC_AHB3ENR_FSMCEN;
|
||
|
__DSB();
|
||
|
}
|
||
|
|
||
|
void display_renderRows(uint8_t startRow, uint8_t endRow)
|
||
|
{
|
||
|
/*
|
||
|
* Put screen data lines back to alternate function mode, since they are in
|
||
|
* common with keyboard buttons and the keyboard driver sets them as inputs.
|
||
|
*/
|
||
|
gpio_setMode(LCD_D0, ALTERNATE);
|
||
|
gpio_setMode(LCD_D1, ALTERNATE);
|
||
|
gpio_setMode(LCD_D2, ALTERNATE);
|
||
|
gpio_setMode(LCD_D3, ALTERNATE);
|
||
|
gpio_setMode(LCD_D4, ALTERNATE);
|
||
|
gpio_setMode(LCD_D5, ALTERNATE);
|
||
|
gpio_setMode(LCD_D6, ALTERNATE);
|
||
|
gpio_setMode(LCD_D7, ALTERNATE);
|
||
|
|
||
|
gpio_clearPin(LCD_CS);
|
||
|
|
||
|
/*
|
||
|
* First of all, convert pixels from little to big endian, for
|
||
|
* compatibility with the display driver. We do this after having brought
|
||
|
* the CS pin low, in this way user code calling the renderingInProgress
|
||
|
* function gets true as return value and does not stomp our work.
|
||
|
*/
|
||
|
for(uint8_t y = startRow; y < endRow; y++)
|
||
|
{
|
||
|
for(uint8_t x = 0; x < SCREEN_WIDTH; x++)
|
||
|
{
|
||
|
size_t pos = x + y * SCREEN_WIDTH;
|
||
|
uint16_t pixel = frameBuffer[pos];
|
||
|
frameBuffer[pos] = __builtin_bswap16(pixel);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Configure start and end rows in display driver */
|
||
|
writeCmd(CMD_RASET);
|
||
|
writeData(0x00);
|
||
|
writeData(startRow);
|
||
|
writeData(0x00);
|
||
|
writeData(endRow);
|
||
|
|
||
|
/* Now, write to memory */
|
||
|
writeCmd(CMD_RAMWR);
|
||
|
|
||
|
/*
|
||
|
* Configure DMA2 stream 7 to send framebuffer data to the screen.
|
||
|
* Both source and destination memory sizes are configured to 8 bit, thus
|
||
|
* we have to set the transfer size to twice the framebuffer size, since
|
||
|
* this one is made of 16 bit variables.
|
||
|
*/
|
||
|
DMA2_Stream7->NDTR = (endRow - startRow) * SCREEN_WIDTH * sizeof(uint16_t);
|
||
|
DMA2_Stream7->PAR = ((uint32_t ) frameBuffer + (startRow * SCREEN_WIDTH
|
||
|
* sizeof(uint16_t)));
|
||
|
DMA2_Stream7->M0AR = LCD_FSMC_ADDR_DATA;
|
||
|
DMA2_Stream7->CR = DMA_SxCR_CHSEL /* Channel 7 */
|
||
|
| DMA_SxCR_PINC /* Increment source pointer */
|
||
|
| DMA_SxCR_DIR_1 /* Memory to memory */
|
||
|
| DMA_SxCR_TCIE /* Transfer complete interrupt */
|
||
|
| DMA_SxCR_TEIE /* Transfer error interrupt */
|
||
|
| DMA_SxCR_EN; /* Start transfer */
|
||
|
|
||
|
OSFlagPend(&renderCompleted, 0x01, 0, OS_OPT_PEND_FLAG_SET_ANY |
|
||
|
OS_OPT_PEND_FLAG_CONSUME |
|
||
|
OS_OPT_PEND_BLOCKING, NULL, &err);
|
||
|
}
|
||
|
|
||
|
void display_render()
|
||
|
{
|
||
|
display_renderRows(0, SCREEN_HEIGHT);
|
||
|
}
|
||
|
|
||
|
bool display_renderingInProgress()
|
||
|
{
|
||
|
/*
|
||
|
* Rendering is in progress if display's chip select is low or a DMA
|
||
|
* transfer is in progress.
|
||
|
*/
|
||
|
bool dmaBusy = (DMA2_Stream7->CR & DMA_SxCR_EN) ? true : false;
|
||
|
return (gpio_readPin(LCD_CS) == 0) || dmaBusy;
|
||
|
}
|
||
|
|
||
|
void *display_getFrameBuffer()
|
||
|
{
|
||
|
return (void *)(frameBuffer);
|
||
|
}
|
||
|
|
||
|
void display_setContrast(uint8_t contrast)
|
||
|
{
|
||
|
/* This controller does not support contrast regulation */
|
||
|
(void) contrast;
|
||
|
}
|