Author Topic: [STM32F4] LCD via SPI  (Read 5440 times)

0 Members and 1 Guest are viewing this topic.

Offline abc12Topic starter

  • Newbie
  • Posts: 2
  • Country: wales
[STM32F4] LCD via SPI
« on: May 22, 2017, 07:54:11 am »
Welcome all!

As a way of exercise I'm trying to convert LCD lib from a web for  a HAL SPI use. I use STM32F429-DISCO board and well, I have no idea what I have done wrong but LCD doesn't work. I have checked that SPI initiates and command string for the LCD init is correct since it's taken from documentation+guides. I would really appreciate help in solving this problem.

main.c
Code: [Select]
#include "stm32f4xx.h"
#include "stm32f429i_discovery.h"
#include "LCD.h"
#include "SPI.h"
#include "fonts.h"


#define USE_MAIN_CLOCK_72MHZ 1

static void SystemClock_Config(void);


int main(void) {
    HAL_Init();

    // Configure the system clock
    SystemClock_Config();
    SystemCoreClockUpdate();
    SysTick_Config(SystemCoreClock / 1000);
   
    BSP_LED_Init(LED4);
    LCD_Init();
   
    for(;;)
    {
    LCD_Putc(120,120, 'c', &Font8, LCD_COLOR_YELLOW);
    }

    return 0;
}


/**
 * @brief  System Clock Configuration
 *         The system Clock is configured as follow :
 *            System Clock source            = PLL (HSE)
 *            SYSCLK(Hz)                     = 180000000
 *            HCLK(Hz)                       = 180000000
 *            AHB Prescaler                  = 1
 *            APB1 Prescaler                 = 4
 *            APB2 Prescaler                 = 2
 *            HSE Frequency(Hz)              = 8000000
 *            PLL_M                          = 8
 *            PLL_N                          = 360
 *            PLL_P                          = 2
 *            PLL_Q                          = 7
 *            VDD(V)                         = 3.3
 *            Main regulator output voltage  = Scale1 mode
 *            Flash Latency(WS)              = 5
 *         The LTDC Clock is configured as follow :
 *            PLLSAIN                        = 192
 *            PLLSAIR                        = 4
 *            PLLSAIDivR                     = 8
 * @param  None
 * @retval None
 *
 * COPYRIGHT(c) 2014 STMicroelectronics
 */

#if 1 == USE_MAIN_CLOCK_180MHZ
static void SystemClock_Config(void) {
    RCC_ClkInitTypeDef RCC_ClkInitStruct;
    RCC_OscInitTypeDef RCC_OscInitStruct;
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;

    /* Enable Power Control clock */
    __PWR_CLK_ENABLE();

    /* The voltage scaling allows optimizing the power consumption when the device is
     clocked below the maximum system frequency, to update the voltage scaling value
     regarding system frequency refer to product datasheet.  */
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /*##-1- System Clock Configuration #########################################*/
    /* Enable HSE Oscillator and activate PLL with HSE as source */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 8;
    RCC_OscInitStruct.PLL.PLLN = 360;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    HAL_PWREx_ActivateOverDrive();

    /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
     clocks dividers */
    RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);

    /*##-2- LTDC Clock Configuration ###########################################*/
    /* LCD clock configuration */
    /* PLLSAI_VCO Input = HSE_VALUE/PLL_M = 1 Mhz */
    /* PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAIN = 192 Mhz */
    /* PLLLCDCLK = PLLSAI_VCO Output/PLLSAIR = 192/4 = 48 Mhz */
    /* LTDC clock frequency = PLLLCDCLK / RCC_PLLSAIDIVR_8 = 48/8 = 6 Mhz */
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
    PeriphClkInitStruct.PLLSAI.PLLSAIN = 192;
    PeriphClkInitStruct.PLLSAI.PLLSAIR = 4;
    PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);
}
#endif



/**
 * SYSCLK = 72
 * HCLK = 72
 * Cortex Timer 72
 * FCLK 72
 * APB1 Peripheral (PCLK1) 36
 * APB1 Timer 72
 * APB2 Peripheral (PCLK2) 72
 * APB2 Timer 72
 *
 */
#if 1 == USE_MAIN_CLOCK_72MHZ
void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;

    /**Configure the main internal regulator output voltage
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 4;
  RCC_OscInitStruct.PLL.PLLN = 72;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 3;
  HAL_RCC_OscConfig(&RCC_OscInitStruct);


    /**Initializes the CPU, AHB and APB busses clocks
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);

  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC;
  PeriphClkInitStruct.PLLSAI.PLLSAIN = 50;
  PeriphClkInitStruct.PLLSAI.PLLSAIR = 2;
  PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2;
  HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

//    /**Configure the Systick interrupt time
//    */
//  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
//
//    /**Configure the Systick
//    */
//  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
//
//  /* SysTick_IRQn interrupt configuration */
//  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
#endif



LCD.h:
Code: [Select]
#ifndef LCD_H_
#define LCD_H_

#include "fonts.h"


#define LCD_WIDTH  240
#define LCD_HEIGHT 320
#define LCD_PIXEL  76800

#define LCD_COLOR_WHITE 0xFFFF
#define LCD_COLOR_BLACK 0x0000
#define LCD_COLOR_RED           0xF800
#define LCD_COLOR_GREEN 0x07E0
#define LCD_COLOR_GREEN2 0xB723
#define LCD_COLOR_BLUE 0x001F
#define LCD_COLOR_BLUE2 0x051D
#define LCD_COLOR_YELLOW 0xFFE0
#define LCD_COLOR_ORANGE 0xFBE4
#define LCD_COLOR_CYAN 0x07FF
#define LCD_COLOR_MAGENTA 0xA254
#define LCD_COLOR_GRAY 0x7BEF
#define LCD_COLOR_BROWN 0xBBCA
#define LCD_TRANSPARENT 0x80000000

typedef enum {
LCD_Orientation_Portrait_1,
LCD_Orientation_Portrait_2,
LCD_Orientation_Landscape_1,
LCD_Orientation_Landscape_2
} LCD_Orientation_t;

void LCD_Init(void);
int LCD_InitLCD(void);
void LCD_SendData(uint8_t data);
void LCD_SendCommand(uint8_t data);
void LCD_SetCursor(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void LCD_Pixel(uint16_t x, uint16_t y, uint32_t color);
void LCD_Fill(uint32_t color);
void LCD_Rotate(LCD_Orientation_t orientation);
void LCD_Putc(uint16_t x, uint16_t y, char c, sFONT* font, uint32_t foreground);
void LCD_Puts(uint16_t x, uint16_t y, char* str, sFONT *font, uint32_t foreground);
void LCD_GetStringSize(char* str, sFONT* font, uint16_t* width, uint16_t* height);
void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint32_t color);
void LCD_DrawRectangle(uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1, uint32_t color);
void LCD_DrawCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color);
void LCD_DrawFilledCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color);
void LCD_DisplayOn(void);
void LCD_DisplayOff(void);
void Delay(volatile unsigned int delay);

#endif /* LCD_H_ */

SPI.h:
Code: [Select]
#ifndef SPI_H_
#define SPI_H_

#include "stm32f4xx_hal.h"

#define SPIx                             SPI5
#define SPIxCLK_ENABLE()                 __HAL_RCC_SPI5_CLK_ENABLE();
#define SPIxCLK_DISABLE()                __HAL_RCC_SPI5_CLK_DISABLE();
#define SPIx_SCK_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOF_CLK_ENABLE();
#define SPIx_MISO_GPIO_CLK_ENABLE()      __HAL_RCC_GPIOF_CLK_ENABLE();
#define SPIxMOSI_GPIO_CLK_ENABLE()       __HAL_RCC_GPIOF_CLK_ENABLE();
#define WRX_GPIO_CLK_ENABLE()            __HAL_RCC_GPIOD_CLK_ENABLE();
#define CS_GPIO_CLK_ENABLE()             __HAL_RCC_GPIOC_CLK_ENABLE();
#define RST_GPIO_CLK_ENABLE()            __HAL_RCC_GPIOD_CLK_ENABLE();

#define SPIx_FORCE_RESET()               __SPI5_FORCE_RESET()
#define SPIx_RELEASE_RESET()             __SPI5_RELEASE_RESET

#define SPIx_SCK_PIN                     GPIO_PIN_7
#define SPIx_SCK_GPIO_PORT               GPIOF
#define SPIx_SCK_AF                      GPIO_AF5_SPI5
#define SPIx_MISO_PIN                    GPIO_PIN_8
#define SPIx_MISO_GPIO_PORT              GPIOF
#define SPIx_MISO_AF                     GPIO_AF5_SPI5
#define SPIx_MOSI_PIN                    GPIO_PIN_9
#define SPIx_MOSI_GPIO_PORT              GPIOF
#define SPIx_MOSI_AF                     GPIO_AF5_SPI5

#define WRX_PIN GPIO_PIN_13
#define WRX_GPIO_PORT                    GPIOD
#define CS_PIN                           GPIO_PIN_2
#define CS_GPIO_PORT                     GPIOC
#define RST_PIN                          GPIO_PIN_12
#define RST_GPIO_PORT                    GPIOD

#define DMAx                             DMA2
#define DMAx_CLOCK_ENABLE()              __HAL_RCC_DMA2_CLK_ENABLE();
#define DMAx_RX_STREAM                   DMA2_Stream3
#define DMAx_RX_CHANNEL                  DMA_CHANNEL_2
#define DMAx_TX_STREAM                   DMA2_Stream4
#define DMAx_TX_CHANNEL                  DMA_CHANNEL_2
#define DMAx_CLOCK_ENABLE()              __HAL_RCC_DMA2_CLK_ENABLE();


#define BUFFERSIZE                      (COUNTOF(aTxBuffer)-1)
#define COUNTOF(__BUFFER__)             (sizeof(__BUFFER__) / sizeof(*(__BUFFER__)))

void GPIO_SPI_DMA_Init(void);
void SPI_Init(void);
void DMA_Init(void);
void GPIO_Init(void);
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi);
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi);



LCD.c:
Code: [Select]
#include <stdlib.h>
#include "LCD.h"
#include "SPI.h"
#include "ili9341.h"
#include "stm32f4xx_hal.h"


#define WRX_SET()          HAL_GPIO_WritePin(WRX_GPIO_PORT, WRX_PIN, 1);
#define WRX_RESET()        HAL_GPIO_WritePin(WRX_GPIO_PORT, WRX_PIN, 0);
#define CS_SET()           HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, 1);
#define CS_RESET()         HAL_GPIO_WritePin(CS_GPIO_PORT, CS_PIN, 0);
#define RST_SET()          HAL_GPIO_WritePin(RST_GPIO_PORT, RST_PIN, 1);
#define RST_RESET()        HAL_GPIO_WritePin(RST_GPIO_PORT, RST_PIN, 0);

typedef enum {
LCD_Landscape,
LCD_Portrait
}LCD_Orientation;

typedef struct {
uint16_t width;
uint16_t height;
LCD_Orientation orientation;
}LCD_Options_t;

GPIO_InitTypeDef GPIO_InitStruct;
SPI_HandleTypeDef hspi;
DMA_HandleTypeDef hdma_spi_rx;
DMA_HandleTypeDef hdma_spi_tx;

uint16_t LCD_x;
uint16_t LCD_y;
LCD_Options_t LCD_Options;
uint8_t Data_From_Puts = 0;

void LCD_Init(void) {
GPIO_Init();
CS_SET();
DMA_Init();
SPI_Init();
LCD_InitLCD();
LCD_x = LCD_y = 0;
LCD_Options.width = LCD_WIDTH;
LCD_Options.height = LCD_HEIGHT;
LCD_Options.orientation = LCD_Portrait;
LCD_Fill(LCD_COLOR_RED);
}

int LCD_InitLCD(void) {
RST_RESET();
Delay(20000);
RST_SET();
Delay(20000);
LCD_SendCommand(LCD_SWRESET);
Delay(50000);
LCD_SendCommand(LCD_POWERA);
LCD_SendData(0x39);
LCD_SendData(0x2C);
LCD_SendData(0x00);
LCD_SendData(0x34);
LCD_SendData(0x02);
LCD_SendCommand(LCD_POWERB);
LCD_SendData(0x00);
LCD_SendData(0xC1);
LCD_SendData(0x30);
LCD_SendCommand(LCD_DTCA);
LCD_SendData(0x85);
LCD_SendData(0x00);
LCD_SendData(0x78);
LCD_SendCommand(LCD_DTCB);
LCD_SendData(0x00);
LCD_SendData(0x00);
LCD_SendCommand(LCD_POWER_SEQ);
LCD_SendData(0x64);
LCD_SendData(0x03);
LCD_SendData(0x12);
LCD_SendData(0x81);
LCD_SendCommand(LCD_PRC);
LCD_SendData(0x20);
LCD_SendCommand(LCD_POWER1);
LCD_SendData(0x23);
LCD_SendCommand(LCD_POWER2);
LCD_SendData(0x10);
LCD_SendCommand(LCD_VCOM1);
LCD_SendData(0x3E);
LCD_SendData(0x28);
LCD_SendCommand(LCD_VCOM2);
LCD_SendData(0x86);
LCD_SendCommand(LCD_MAC);
LCD_SendData(0x48);
LCD_SendCommand(LCD_PIXEL_FORMAT);
LCD_SendData(0x55);
LCD_SendCommand(LCD_FRMCTR1);
LCD_SendData(0x00);
LCD_SendData(0x18);
LCD_SendCommand(LCD_DFC);
LCD_SendData(0x08);
LCD_SendData(0x82);
LCD_SendData(0x27);
LCD_SendCommand(LCD_3GAMMA_EN);
LCD_SendData(0x00);
LCD_SendCommand(LCD_COLUMN_ADDR);
LCD_SendData(0x00);
LCD_SendData(0x00);
LCD_SendData(0x00);
LCD_SendData(0xEF);
LCD_SendCommand(LCD_PAGE_ADDR);
LCD_SendData(0x00);
LCD_SendData(0x00);
LCD_SendData(0x01);
LCD_SendData(0x3F);
LCD_SendCommand(LCD_GAMMA);
LCD_SendData(0x01);
LCD_SendCommand(LCD_PGAMMA);
LCD_SendData(0x0F);
LCD_SendData(0x31);
LCD_SendData(0x2B);
LCD_SendData(0x0C);
LCD_SendData(0x0E);
LCD_SendData(0x08);
LCD_SendData(0x4E);
LCD_SendData(0xF1);
LCD_SendData(0x37);
LCD_SendData(0x07);
LCD_SendData(0x10);
LCD_SendData(0x03);
LCD_SendData(0x0E);
LCD_SendData(0x09);
LCD_SendData(0x00);
LCD_SendCommand(LCD_NGAMMA);
LCD_SendData(0x00);
LCD_SendData(0x0E);
LCD_SendData(0x14);
LCD_SendData(0x03);
LCD_SendData(0x11);
LCD_SendData(0x07);
LCD_SendData(0x31);
LCD_SendData(0xC1);
LCD_SendData(0x48);
LCD_SendData(0x08);
LCD_SendData(0x0F);
LCD_SendData(0x0C);
LCD_SendData(0x31);
LCD_SendData(0x36);
LCD_SendData(0x0F);
LCD_SendCommand(LCD_SLEEP_OUT);
Delay(1000000);
LCD_SendCommand(LCD_DISPLAY_ON);
LCD_SendCommand(LCD_GRAM);
return 1;
}

void LCD_DisplayOn(void){
LCD_SendCommand(LCD_DISPLAY_ON);
}

void LCD_DisplayOff(void) {
LCD_SendCommand(LCD_DISPLAY_OFF);
}

void LCD_SendCommand(uint8_t data) {
WRX_RESET();
CS_RESET();
HAL_SPI_Transmit_IT(&hspi, &data, 1);
CS_SET();
}

void LCD_SendData(uint8_t data) {
WRX_SET();
CS_RESET();
HAL_SPI_Transmit_IT(&hspi, &data, 1);
CS_SET();
}

void LCD_DrawPixel(uint16_t x, uint16_t y, uint32_t color) {
LCD_SetCursor(x,y,x,y);
LCD_SendCommand(LCD_GRAM);
LCD_SendData(color >> 8);
LCD_SendData(color & 0xFF);
}

void LCD_SetCursor(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
LCD_SendCommand(LCD_COLUMN_ADDR);
LCD_SendData(x1 >> 8);
LCD_SendData(x1 & 0xFF);
LCD_SendData(x2 >> 8);
LCD_SendData(x2 & 0xFF);

LCD_SendCommand(LCD_PAGE_ADDR);
LCD_SendData(y1 >> 8);
LCD_SendData(y1 & 0xFF);
LCD_SendData(y2 >> 8);
LCD_SendData(y2 & 0xFF);
}

void LCD_Fill(uint32_t color) {
uint32_t n;
uint8_t hi,lo;
hi = color >> 8;
lo = color & 0xFF;
LCD_SetCursor(0,0,LCD_Options.width - 1,LCD_Options.height -1);
LCD_SendCommand(LCD_GRAM);
for(n=0;n<LCD_PIXEL;n++) {
LCD_SendData(hi);
LCD_SendData(lo);
}
}

void LCD_Rotate(LCD_Orientation_t orientation) {
LCD_SendCommand(LCD_MAC);
if (orientation == LCD_Orientation_Portrait_1) {
LCD_SendData(0x58);
}
else if (orientation == LCD_Orientation_Portrait_2) {
LCD_SendData(0x88);
}
else if (orientation == LCD_Orientation_Landscape_1) {
LCD_SendData(0x28);
}
else LCD_SendData(0xE8);
if (orientation == LCD_Orientation_Portrait_1 || orientation == LCD_Orientation_Portrait_2) {
LCD_Options.width = LCD_WIDTH;
LCD_Options.height = LCD_HEIGHT;
LCD_Options.orientation = LCD_Portrait;
}
else {
LCD_Options.width = LCD_HEIGHT;
LCD_Options.height = LCD_WIDTH;
LCD_Options.orientation = LCD_Landscape;
}
}

void LCD_Puts(uint16_t x, uint16_t y, char *str, sFONT* font, uint32_t foreground) {
uint16_t startX = x;
LCD_x = x;
LCD_y = y;
while (*str) {
if (*str == '\n') {
LCD_y += font->Height + 1;
if (*(str+1) == '\r') {
LCD_x = 0;
str++;
}
else {
LCD_x = startX;
}
str++;
continue;
}
else if (*str == '\r') {
str++;
continue;
}
LCD_Putc(LCD_x, LCD_y, *str++, font, foreground);
}
}

void LCD_GetStringSize(char *str, sFONT* font, uint16_t *width, uint16_t *height) {
uint16_t w = 0;
*height = font->Height;
while (*str++) {
w += font->Width;
}
*width = w;
}

void LCD_Putc(uint16_t x, uint16_t y, char c, sFONT* font, uint32_t foreground) {
uint32_t i, b, j;
LCD_x = x;
LCD_y = y;
if ((LCD_x + font->Width) > LCD_Options.width) {
LCD_y += font->Width;
LCD_x = 0;
}
for (i=0; i<font->Height; i++) {
b = font->table[(c-32)*font->Height + i];
for (j=0; j<font->Width;j++) {
if ((b<<j) & 0x8000) {
LCD_DrawPixel(LCD_x + j, LCD_y + i, foreground);
}
}
}
LCD_x += font->Width;

}

void LCD_DrawLine(uint16_t X1, uint16_t Y1, uint16_t X2, uint16_t Y2, uint32_t color) {

int16_t deltax = 0, deltay = 0, x = 0, y = 0, xinc1 = 0, xinc2 = 0,
  yinc1 = 0, yinc2 = 0, den = 0, num = 0, numadd = 0, numpixels = 0,
  curpixel = 0;
  deltax = abs(X2 - X1);
  deltay = abs(Y2 - Y1);
  x = X1;
  y = Y1;
  if (X2 >= X1)
  {
    xinc1 = 1;
    xinc2 = 1;
  }
  else
  {
    xinc1 = -1;
    xinc2 = -1;
  }
  if (Y2 >= Y1)
  {
    yinc1 = 1;
    yinc2 = 1;
  }
  else
  {
    yinc1 = -1;
    yinc2 = -1;
  }
  if (deltax >= deltay)
  {
    xinc1 = 0;
    yinc2 = 0;
    den = deltax;
    num = deltax / 2;
    numadd = deltay;
    numpixels = deltax;
  }
  else
  {
    xinc2 = 0;
    yinc1 = 0;
    den = deltay;
    num = deltay / 2;
    numadd = deltax;
    numpixels = deltay;
  }
  for (curpixel = 0; curpixel <= numpixels; curpixel++)
  {
LCD_DrawPixel(x, y, color);
    num += numadd;
    if (num >= den)
    {
      num -= den;
      x += xinc1;
      y += yinc1;
    }
    x += xinc2;
    y += yinc2;
  }
}

void LCD_DrawRectangle(uint16_t x0, uint16_t x1, uint16_t y0, uint16_t y1, uint32_t color) {
LCD_DrawLine(x0,y0,x1,y0,color);
LCD_DrawLine(x0,y0,x0,y1,color);
LCD_DrawLine(x1,y0,x1,y1,color);
LCD_DrawLine(x0,y1,x1,y1,color);
}

void LCD_DrawCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;

    LCD_DrawPixel(x0, y0 + r, color);
    LCD_DrawPixel(x0, y0 - r, color);
    LCD_DrawPixel(x0 + r, y0, color);
    LCD_DrawPixel(x0 - r, y0, color);

    while (x < y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        LCD_DrawPixel(x0 + x, y0 + y, color);
        LCD_DrawPixel(x0 - x, y0 + y, color);
        LCD_DrawPixel(x0 + x, y0 - y, color);
        LCD_DrawPixel(x0 - x, y0 - y, color);

        LCD_DrawPixel(x0 + y, y0 + x, color);
        LCD_DrawPixel(x0 - y, y0 + x, color);
        LCD_DrawPixel(x0 + y, y0 - x, color);
        LCD_DrawPixel(x0 - y, y0 - x, color);
    }
}

void LCD_DrawFilledCircle(int16_t x0, int16_t y0, int16_t r, uint32_t color) {
int16_t f = 1 - r;
int16_t ddF_x = 1;
int16_t ddF_y = -2 * r;
int16_t x = 0;
int16_t y = r;

    LCD_DrawPixel(x0, y0 + r, color);
    LCD_DrawPixel(x0, y0 - r, color);
    LCD_DrawPixel(x0 + r, y0, color);
    LCD_DrawPixel(x0 - r, y0, color);
    LCD_DrawLine(x0 - r, y0, x0 + r, y0, color);

    while (x < y) {
        if (f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;

        LCD_DrawLine(x0 - x, y0 + y, x0 + x, y0 + y, color);
        LCD_DrawLine(x0 + x, y0 - y, x0 - x, y0 - y, color);

        LCD_DrawLine(x0 + y, y0 + x, x0 - y, y0 + x, color);
        LCD_DrawLine(x0 + y, y0 - x, x0 - y, y0 - x, color);
    }
}




void SPI_Init(void) {

  hspi.Instance = SPIx;
  hspi.Init.Mode = SPI_MODE_MASTER;
  hspi.Init.Direction = SPI_DIRECTION_2LINES;
  hspi.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi.Init.NSS = SPI_NSS_SOFT;
  hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
  hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi.Init.CRCPolynomial = 10;
  HAL_SPI_Init(&hspi);

}


void DMA_Init(void) {

/* DMA controller clock enable */
  DMAx_CLOCK_ENABLE();

  /* DMA interrupt init */
  /* DMA2_Stream3_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn);
  /* DMA2_Stream4_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(DMA2_Stream4_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(DMA2_Stream4_IRQn);

}

void GPIO_Init(void) {
WRX_GPIO_CLK_ENABLE();
CS_GPIO_CLK_ENABLE();
RST_GPIO_CLK_ENABLE();

GPIO_InitStruct.Pin = WRX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(WRX_GPIO_PORT, &GPIO_InitStruct);

GPIO_InitStruct.Pin = CS_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
HAL_GPIO_Init(CS_GPIO_PORT, &GPIO_InitStruct);

GPIO_InitStruct.Pin = RST_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW ;
HAL_GPIO_Init(RST_GPIO_PORT, &GPIO_InitStruct);
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi) {

SPIxCLK_ENABLE();
SPIx_SCK_GPIO_CLK_ENABLE();
SPIx_MISO_GPIO_CLK_ENABLE();
SPIxMOSI_GPIO_CLK_ENABLE();


GPIO_InitStruct.Pin = SPIx_SCK_PIN|SPIx_MISO_PIN|SPIx_MOSI_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = SPIx_SCK_AF;
HAL_GPIO_Init(SPIx_SCK_GPIO_PORT, &GPIO_InitStruct);

hdma_spi_rx.Instance = DMAx_RX_STREAM;
hdma_spi_rx.Init.Channel = DMAx_RX_CHANNEL;
hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_rx.Init.Mode = DMA_NORMAL;
hdma_spi_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi_rx);

__HAL_LINKDMA(hspi,hdmarx,hdma_spi_rx);

hdma_spi_tx.Instance = DMAx_TX_STREAM;
hdma_spi_tx.Init.Channel = DMAx_TX_CHANNEL;
hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi_tx.Init.Mode = DMA_NORMAL;
hdma_spi_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi_tx);

__HAL_LINKDMA(hspi,hdmatx,hdma_spi_tx);
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi) {

SPIxCLK_DISABLE();
HAL_GPIO_DeInit(SPIx_SCK_GPIO_PORT, SPIx_SCK_PIN);
HAL_GPIO_DeInit(SPIx_MISO_GPIO_PORT, SPIx_MISO_PIN);
HAL_GPIO_DeInit(SPIx_MOSI_GPIO_PORT, SPIx_MOSI_PIN);


HAL_DMA_DeInit(hspi->hdmarx);
HAL_DMA_DeInit(hspi->hdmatx);
}

void Delay(volatile unsigned int delay) {
for(;delay != 0; delay--);
}
 

Offline FreddyVictor

  • Regular Contributor
  • *
  • Posts: 164
  • Country: gb
Re: [STM32F4] LCD via SPI
« Reply #1 on: May 22, 2017, 12:12:53 pm »
The STM32F429-Discovery uses a parallel interface for the actual colour data sent to the screen.
Take a look at the user manual page33

The SPI code you're using I think is probably meant for using with the ILI9341 type displays
You could always connect one of these to a spare SPI slot on the board

Incidentally, having messed around with these things, that library code is comprehensive and convenient, but, will lack alot in speed since it does alot of unnecessary pin toggling for virtually every byte sent.
my early code was taking 0.5s just to clear a screen, but after improvements takes nearer 0.12s
 

Offline abc12Topic starter

  • Newbie
  • Posts: 2
  • Country: wales
Re: [STM32F4] LCD via SPI
« Reply #2 on: May 22, 2017, 02:05:05 pm »
Are you sure? Yes, stm examples use parallel interface for LCD but it's still ILI9341 connected through SPI5 to board so I don't see why it shouldn't work (but well, it doesn't in this form...).
« Last Edit: May 22, 2017, 02:09:12 pm by abc12 »
 

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: [STM32F4] LCD via SPI
« Reply #3 on: May 22, 2017, 05:49:48 pm »
The STM32F429-Discovery uses a parallel interface for the actual colour data sent to the screen.
Take a look at the user manual page33
Right, but you can see that the 9341 controller is wired for SPI, as the IM0...IM3 control pins are set to 0b0110 (as duly noted in the text box).
The use of parallel RGB interface is set up by SW, in the BSP part of the Cube, in the initialization function:
Quote
...
  ili9341_WriteReg(LCD_RGB_INTERFACE); // 0xB0
  ili9341_WriteData(0xC2);
...
The default value for the relevant bits is 0, so the SPI should suffice.

To the OP: if have some time later, I might have a look at the code and try it on my board. No guarantees, though! :=\
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: abc12

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: [STM32F4] LCD via SPI
« Reply #4 on: May 22, 2017, 09:21:18 pm »
OK, let's go for it!

First of all, the initialization sequence: each TFT panel has its own specific settings, so my best bet was to copy the init sequence from the Cube BSP, as many of the values were quite off (e.g. the VCOMs).

Of course, the RGB interface must be disabled, so the relevant command is changed, and the one to set the pixel format to 16bit is added.

BTW, the original code also toggled a pin as reset, but that pin is RDX, not used in the SPI case.
Code: [Select]
int LCD_InitLCD(void) {
  // newbrain
  //
  // What's this supposed to be? in the BSP, but not in the datasheet!
  //LCD_SendCommand(0xCA);
  //LCD_SendData(0xC3);
  //LCD_SendData(0x08);
  //LCD_SendData(0x50);
  LCD_SendCommand(LCD_POWERB);
  LCD_SendData(0x00);
  LCD_SendData(0xC1);
  LCD_SendData(0x30);
  LCD_SendCommand(LCD_POWER_SEQ);
  LCD_SendData(0x64);
  LCD_SendData(0x03);
  LCD_SendData(0x12);
  LCD_SendData(0x81);
  LCD_SendCommand(LCD_DTCA);
  LCD_SendData(0x85);
  LCD_SendData(0x00);
  LCD_SendData(0x78);
  LCD_SendCommand(LCD_POWERA);
  LCD_SendData(0x39);
  LCD_SendData(0x2C);
  LCD_SendData(0x00);
  LCD_SendData(0x34);
  LCD_SendData(0x02);
  LCD_SendCommand(LCD_PRC);
  LCD_SendData(0x20);
  LCD_SendCommand(LCD_DTCB);
  LCD_SendData(0x00);
  LCD_SendData(0x00);
  LCD_SendCommand(LCD_FRMCTR1);
  LCD_SendData(0x00);
  LCD_SendData(0x1B);
  LCD_SendCommand(LCD_DFC);
  LCD_SendData(0x0A);
  LCD_SendData(0xA2);
  LCD_SendCommand(LCD_POWER1);
  LCD_SendData(0x10);
  LCD_SendCommand(LCD_POWER2);
  LCD_SendData(0x10);
  LCD_SendCommand(LCD_VCOM1);
  LCD_SendData(0x45);
  LCD_SendData(0x15);
  LCD_SendCommand(LCD_VCOM2);
  LCD_SendData(0x90);
  LCD_SendCommand(LCD_MAC);
  LCD_SendData(0xC8);
  LCD_SendCommand(LCD_3GAMMA_EN);
  LCD_SendData(0x00);
  // Not needed, we don't use RGB interface
  //LCD_SendCommand(LCD_RGB_INTERFACE);
  //LCD_SendData(0xC2);
  LCD_SendCommand(LCD_DFC);
  LCD_SendData(0x0A);
  LCD_SendData(0xA7);
  LCD_SendData(0x27);
  LCD_SendData(0x04);
 
 
  LCD_SendCommand(LCD_PIXEL_FORMAT);
  LCD_SendData(0x55);

  /* Colomn address set */
  LCD_SendCommand(LCD_COLUMN_ADDR);
  LCD_SendData(0x00);
  LCD_SendData(0x00);
  LCD_SendData(0x00);
  LCD_SendData(0xEF);
  /* Page address set */
  LCD_SendCommand(LCD_PAGE_ADDR);
  LCD_SendData(0x00);
  LCD_SendData(0x00);
  LCD_SendData(0x01);
  LCD_SendData(0x3F);
  LCD_SendCommand(LCD_INTERFACE);
  LCD_SendData(0x01);
  LCD_SendData(0x00);
  // newbrain: change from 0x02 (RGB) to 0x00 (internal clocking)
  LCD_SendData(0x00);
 
  LCD_SendCommand(LCD_GRAM);
  HAL_Delay(200);
 
  LCD_SendCommand(LCD_GAMMA);
  LCD_SendData(0x01);
 
  LCD_SendCommand(LCD_PGAMMA);
  LCD_SendData(0x0F);
  LCD_SendData(0x29);
  LCD_SendData(0x24);
  LCD_SendData(0x0C);
  LCD_SendData(0x0E);
  LCD_SendData(0x09);
  LCD_SendData(0x4E);
  LCD_SendData(0x78);
  LCD_SendData(0x3C);
  LCD_SendData(0x09);
  LCD_SendData(0x13);
  LCD_SendData(0x05);
  LCD_SendData(0x17);
  LCD_SendData(0x11);
  LCD_SendData(0x00);
  LCD_SendCommand(LCD_NGAMMA);
  LCD_SendData(0x00);
  LCD_SendData(0x16);
  LCD_SendData(0x1B);
  LCD_SendData(0x04);
  LCD_SendData(0x11);
  LCD_SendData(0x07);
  LCD_SendData(0x31);
  LCD_SendData(0x33);
  LCD_SendData(0x42);
  LCD_SendData(0x05);
  LCD_SendData(0x0C);
  LCD_SendData(0x0A);
  LCD_SendData(0x28);
  LCD_SendData(0x2F);
  LCD_SendData(0x0F);
 
  LCD_SendCommand(LCD_SLEEP_OUT);
  HAL_Delay(200);
  LCD_SendCommand(LCD_DISPLAY_ON);
  /* GRAM start writing */
  LCD_SendCommand(LCD_GRAM);

  return 1;
}


Second, the use of the HAL:
You should use the regular HAL_SPI_Transmit rather the _IT variant, or provide an ISR for the SPI interrupt.
Calling HAL_SPI_Transmit_IT() without waiting for the transmission to finish (as done in the code) will most assuredly give overrun errors, and, without a definition of the SPI ISR, one will end up in the default handler provided by the startup file.
Code: [Select]
void LCD_SendCommand(uint8_t data) {
  WRX_RESET();
  CS_RESET();
//  newbrain 
  HAL_SPI_Transmit(&hspi, &data, 1, 500);
//  HAL_SPI_Transmit_IT(&hspi, &data, 1);
  CS_SET();
}

void LCD_SendData(uint8_t data) {
  WRX_SET();
  CS_RESET();
//  newbrain 
  HAL_SPI_Transmit(&hspi, &data, 1, 500);
//  HAL_SPI_Transmit_IT(&hspi, &data, 1);
  CS_SET();
}

I see also that DMA channels are setup, but not used. Consider that if you intend to read from the 9341, the SPI must be configured for half-duplex (i.e. same line for MISO/MOSI), unless you change the IM0..3 bits to 0b1110 (soldering iron programming, you can find the pullup and pulldown resistors on the bottom of the baord, close to PC15 pin).

Then, the character drawing routine contains a couple of minor faults, see below:
Code: [Select]
void LCD_Putc(uint16_t x, uint16_t y, char c, sFONT* font, uint32_t foreground) {
  uint32_t i, b, j;
  LCD_x = x;
  LCD_y = y;
  if ((LCD_x + font->Width) > LCD_Options.width) {
    // newbrain: this should be the height!
    // LCD_y += font->Width;
    LCD_y += font->Height;
    LCD_x = 0;
  }
  for (i = 0; i < font->Height; i++) {
    b = font->table[(c - 32)*font->Height + i];
    for (j = 0; j < font->Width; j++) {
      // newbrain: 0x8000 is too much, if you are using font8,
      // the whole loop should be adjusted depending on the font width!
      //if ((b << j) & 0x8000) {
        if ((b << j) & 0x80) {
        LCD_DrawPixel(LCD_x + j, LCD_y + i, foreground);
      }
    }
  }
  LCD_x += font->Width;

}

Another minor error: LCD.h declares LCD_Pixel(), but LCD.h defines LCD_DrawPixel()!


For me it now works as expected, hope this helps!

Oh, and welcome to the forum!
« Last Edit: May 22, 2017, 09:27:42 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: abc12

Online newbrain

  • Super Contributor
  • ***
  • Posts: 1719
  • Country: se
Re: [STM32F4] LCD via SPI
« Reply #5 on: May 23, 2017, 09:19:52 am »
OP asked for some help with different fonts...
Here you go.

No optimization has been done (there are several opportunities), but I hope it is at least clear enough.

This is untested code!
If your cat catches fire or you grow green horns, it's not my fault.

Code: [Select]
void LCD_Putc(uint16_t x, uint16_t y, char c, sFONT *font, uint32_t foreground)
{
  if ((x + font->Width) > LCD_Options.width)
  {
      // Here, a check on display height would be in order!
    y += font->Height;
    x = 0;
  }
  // How many bytes in one font line?
  uint32_t lineSize = (font->Width + 7) / 8;
  // char offset in the table
  uint32_t charOffset = (c - 32) * font->Height * lineSize;
  // Outer loop, repeat for every line of lineSize bytes in the font
  for (uint32_t line = 0; line < font->Height; line++)
  {
      // Loop over the bytes in one line
    for (uint32_t byte = 0; byte < lineSize; byte++)
    {
        // How many bits are used in this byte?
      uint32_t stopBit = 8;
      // Last byte in line?
      if (byte == lineSize - 1)
        stopBit = font->Width % 8;
    // Get the byte
      uint32_t value = font->table[charOffset + line*lineSize + byte];
      for (uint32_t bit = 0; bit < stopBit; bit++)
      {
          // Draw the pixel, if needed
        if ((value << bit) & 0x80)
        {
          LCD_DrawPixel(x + byte * 8 + bit, y + line, foreground);
        }
      }
    }
  }
}

Edit: x update fixed.
Edit2:
Quote
My cat caught fire   ;)
I'm terribly sorry for the poor animal. :'(
I hope the green horns at least match your hairstyle and colour.
Fixed for real this time (pinky swear), and lightly tested for Font8-24.
It was, admittedly, written hastily (work break).
« Last Edit: May 23, 2017, 04:13:12 pm by newbrain »
Nandemo wa shiranai wa yo, shitteru koto dake.
 
The following users thanked this post: abc12

Offline FreddyVictor

  • Regular Contributor
  • *
  • Posts: 164
  • Country: gb
Re: [STM32F4] LCD via SPI
« Reply #6 on: May 23, 2017, 02:58:51 pm »
My cat caught fire   ;)

slightly revised code for LCD_Putc()
Code: [Select]
void LCD_Putc(uint16_t x, uint16_t y, char c, sFONT *font, uint32_t foreground)
{
    if ((x + font->Width) > LCD_Options.width)
    {
        // Here, a check on display height would be in order!
        y += font->Height;
        x = 0;
    }
    // How many bytes in one font line?
    uint32_t lineSize = (font->Width + 7) / 8;
    // char offset in the table
    uint32_t charOffset = (c - 32) * font->Height * lineSize;
    // Outer loop, repeat for every line of lineSize bytes in the font
    for (uint32_t line = 0; line < font->Height; line ++)
    {
        // get ptr to start of this line
        const uint8_t * value = font->table+(charOffset + line*lineSize);
        // terrible code but it works
        uint8_t bit = 0;
        while(bit<font->Width)
        {
            if ((*value << (bit%8)) & 0x80)
            {
                LCD_DrawPixel(x + bit, y + line, foreground);
            }
            if (++bit%8==0) { value++; } // if end-of byte, skip to start of next byte
        }
    }
}

also slight mod needed for LCD_Puts():
Code: [Select]
LCD_Putc(LCD_x, LCD_y, *str++, font, foreground);
LCD_x+=font->Width; //<-- FV added line

appears to work ok with 8,12 & 16 font size
 
The following users thanked this post: abc12


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf