cancel
Showing results for 
Search instead for 
Did you mean: 

How can I update SPI ILI9341 screen on every timer interrupt?

cockatoo
Associate III

I have an ILI9341 SPI screen and a small self-made library that can display different numbers on the screen. I want to be able to update the screen (display a new number) every time there is an interrupt. I have tested the screen functions independently, and they work properly. But when I call them from the interrupt handler, they fail. The board is STM32F407G-DISC1.

Timer configuration

static void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */

  /* USER CODE END TIM2_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 999;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 335900;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */

  /* USER CODE END TIM2_Init 2 */

}

Timer interrupt

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
	//HAL_SPI_TransmitReceive_DMA(&hspi1, xyz_addr, xyz_data, 6);
	if ((new_step == 1) && (draw_ready == 1)) {
		draw_number(steps_count, 12, &hspi2);
	}
	new_step = 0;
}

Display functions (they use polling to interact with the screen, no interrupts or dma) 

#include "display.h"
#define DC_GPIO_PORT GPIOB
#define DC_GPIO_PIN GPIO_PIN_14
#define ILI9341_WIDTH  240
#define ILI9341_HEIGHT 320

//uint8_t DIGITS_CODES[10] = {126, 48, 109, 121, 55, 91, 95, 112, 127, 125};
uint8_t DIGITS_CODES[10] = {
    63,  // 0 = A B C D E F
    6,   // 1 = B C
    91,  // 2 = A B D E G
    79,  // 3 = A B C D G
    102, // 4 = B C F G
    109, // 5 = A C D F G
    125, // 6 = A C D E F G
    7,   // 7 = A B C
    127, // 8 = A B C D E F G
    111  // 9 = A B C D F G
};

void Send_Command(uint8_t command, uint8_t *args, int num_args, SPI_HandleTypeDef *hspi) {
	HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(DC_GPIO_PORT, DC_GPIO_PIN, GPIO_PIN_RESET);
	uint8_t cmd[1] = {command};
	HAL_SPI_Transmit(hspi,  cmd, 1, 100);
	HAL_GPIO_WritePin(DC_GPIO_PORT, DC_GPIO_PIN, GPIO_PIN_SET);
	HAL_SPI_Transmit(hspi, args, num_args, 100);
	HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_SET);
}

void Send_Command_NoArgs(uint8_t command, SPI_HandleTypeDef *hspi) {
	HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(DC_GPIO_PORT, DC_GPIO_PIN, GPIO_PIN_RESET);
	uint8_t cmd[1] = {command};
	HAL_SPI_Transmit(hspi,  cmd, 1, 100);
	HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_SET);
}

void Send_Command_NoArgs_No_NSS_Set(uint8_t command, SPI_HandleTypeDef *hspi) {
	HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_RESET);
	HAL_GPIO_WritePin(DC_GPIO_PORT, DC_GPIO_PIN, GPIO_PIN_RESET);
	uint8_t cmd[1] = {command};
	HAL_SPI_Transmit(hspi,  cmd, 1, 100);
	//HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_SET);
}

uint32_t min(uint32_t a, uint32_t b) {
	if (a < b) {
		return a;
	}
	return b;
}

void Write_Rectangle(uint16_t row_lower, uint16_t row_higher, uint16_t col_lower, uint16_t col_higher, uint16_t color, SPI_HandleTypeDef *hspi2) {
	//16 bit/pixel color order (R:5-bit, G:6-bit, B:5-bit)

	//1.Set column
	uint8_t col_params[4] = {(uint8_t)(col_lower >> 8), (uint8_t)(col_lower & 0x00FF),
								(uint8_t)(col_higher >> 8), (uint8_t)(col_higher & 0x00FF)};
	Send_Command(SET_COL_CMD, col_params, 4, hspi2);

	//2.Set row
	uint8_t row_params[4] = {(uint8_t)(row_lower >> 8), (uint8_t)(row_lower & 0x00FF),
							(uint8_t)(row_higher >> 8), (uint8_t)(row_higher & 0x00FF)};
	Send_Command(SET_ROW_CMD, row_params, 4, hspi2);

	//3.Set color
	Send_Command_NoArgs_No_NSS_Set(SET_COLOR_CMD, hspi2);
	// Compute rectangle size
	uint32_t width  = col_higher - col_lower + 1;
	uint32_t height = row_higher - row_lower + 1;
	uint32_t pixels = width * height;
	// Send color repeatedly
	HAL_GPIO_WritePin(DC_GPIO_PORT, DC_GPIO_PIN, GPIO_PIN_SET);
	int array_size = min(64, pixels * 2);
	uint8_t pix_array[64];
	for (int i = 0; i < array_size; i++) {
		if (i % 2 == 0) {
			pix_array[i] = (uint8_t)(color >> 8);
		}
		else {
			pix_array[i] = (uint8_t)(color & 0xFF);
		}
	}
	if (array_size < 64) {
		HAL_SPI_Transmit(hspi2, pix_array, array_size, 100);
	}
	else {
		uint32_t pixels_written = 0;
		while (pixels_written + array_size < pixels * 2) {
			HAL_SPI_Transmit(hspi2, pix_array, array_size, 100);
			pixels_written += array_size;
		}
		HAL_SPI_Transmit(hspi2, pix_array, pixels * 2 - pixels_written, 100);
	}
	HAL_GPIO_WritePin(NSS_GPIO_PORT, NSS_GPIO_PIN, GPIO_PIN_SET);
}



void draw_digit(uint16_t x, uint16_t y, uint32_t size, uint8_t digit, uint16_t color, SPI_HandleTypeDef *hspi2) {
	if (digit > 9) {
		return;
	}
	uint8_t digit_code = DIGITS_CODES[digit];
	uint8_t width = size / 6;
	for (int i = 0; i < 7; i++) {
		if (digit_code & 1) {
		            switch (i) {

		                case 0: // A (top)
		                    Write_Rectangle(
		                        y,
		                        y + width,
		                        x,
		                        x + size,
		                        color, hspi2
		                    );
		                    break;

		                case 1: // B (top right)
		                    Write_Rectangle(
		                        y,
		                        y + size,
		                        x + size,
		                        x + size + width,
		                        color, hspi2
		                    );
		                    break;

		                case 2: // C (bottom right)
		                    Write_Rectangle(
		                        y + size,
		                        y + size * 2,
		                        x + size,
		                        x + size + width,
		                        color, hspi2
		                    );
		                    break;

		                case 3: // D (bottom)
		                    Write_Rectangle(
		                        y + size * 2 - width,
		                        y + size * 2,
		                        x,
		                        x + size,
		                        color, hspi2
		                    );
		                    break;

		                case 4: // E (bottom left)
		                    Write_Rectangle(
		                        y + size,
		                        y + size * 2,
		                        x,
		                        x + width,
		                        color, hspi2
		                    );
		                    break;

		                case 5: // F (top left)
		                    Write_Rectangle(
		                        y,
		                        y + size,
		                        x,
		                        x + width,
		                        color, hspi2
		                    );
		                    break;

		                case 6: // G (middle)
		                    Write_Rectangle(
		                        y + size - width / 2,
		                        y + size + width -  width / 2,
		                        x,
		                        x + size,
		                        color, hspi2
		                    );
		                    break;
		            }
		}
		digit_code = digit_code >> 1;
	}
}

void draw_number(uint32_t number, uint32_t size, SPI_HandleTypeDef *hspi2) {
	 // Find highest power of 10
	 uint32_t value = number;
	 uint32_t div = 1;
	 uint16_t x = 5;
	 uint16_t y = 5;
	 uint16_t color = 0;

	 while (value / div >= 10) {
		 div *= 10;
	 }
	 while (div != 0) {
		 uint8_t digit = (uint8_t)(value / div);
		 draw_digit(x, y, size, digit, color, hspi2);
		 value %= div;
		 div /= 10;
		 x += size + 5;
	 }
}

//actual

///https://github.com/martnak/STM32-ILI9341/blob/master/Src/ILI9341/ILI9341_STM32_Driver.c
void ILI9341_Init(SPI_HandleTypeDef *hspi2)
{
    // Hardware reset
    HAL_GPIO_WritePin(RST_GPIO_PORT, RST_GPIO_PIN, GPIO_PIN_RESET);
    HAL_Delay(10);
    HAL_GPIO_WritePin(RST_GPIO_PORT, RST_GPIO_PIN, GPIO_PIN_SET);
    HAL_Delay(120);

    // Software reset
    Send_Command_NoArgs(0x01, hspi2);
    HAL_Delay(1000);

    // POWER CONTROL A
    uint8_t pwrA[5] = {0x39, 0x2C, 0x00, 0x34, 0x02};
    Send_Command(0xCB, pwrA, 5, hspi2);

    // POWER CONTROL B
    uint8_t pwrB[3] = {0x00, 0xC1, 0x30};
    Send_Command(0xCF, pwrB, 3, hspi2);

    // DRIVER TIMING CONTROL A
    uint8_t dtca[3] = {0x85, 0x00, 0x78};
    Send_Command(0xE8, dtca, 3, hspi2);

    // DRIVER TIMING CONTROL B
    uint8_t dtcb[2] = {0x00, 0x00};
    Send_Command(0xEA, dtcb, 2, hspi2);

    // POWER ON SEQUENCE CONTROL
    uint8_t pwrSeq[4] = {0x64, 0x03, 0x12, 0x81};
    Send_Command(0xED, pwrSeq, 4, hspi2);

    // PUMP RATIO CONTROL
    uint8_t pump[1] = {0x20};
    Send_Command(0xF7, pump, 1, hspi2);

    // POWER CONTROL 1 (VRH)
    uint8_t pwr1[1] = {0x23};
    Send_Command(0xC0, pwr1, 1, hspi2);

    // POWER CONTROL 2 (SAP, BT)
    uint8_t pwr2[1] = {0x10};
    Send_Command(0xC1, pwr2, 1, hspi2);

    // VCOM CONTROL 1
    uint8_t vcom1[2] = {0x3E, 0x28};
    Send_Command(0xC5, vcom1, 2, hspi2);

    // VCOM CONTROL 2
    uint8_t vcom2[1] = {0x86};
    Send_Command(0xC7, vcom2, 1, hspi2);

    // MEMORY ACCESS CONTROL (rotation)
    uint8_t mac[1] = {0x48};
    Send_Command(0x36, mac, 1, hspi2);

    // PIXEL FORMAT (RGB565)
    uint8_t pixel_fmt[1] = {0x55};
    Send_Command(0x3A, pixel_fmt, 1, hspi2);

    // FRAME RATE CONTROL
    uint8_t frmctr[2] = {0x00, 0x18};
    Send_Command(0xB1, frmctr, 2, hspi2);

    // DISPLAY FUNCTION CONTROL
    uint8_t dfc[3] = {0x08, 0x82, 0x27};
    Send_Command(0xB6, dfc, 3, hspi2);

    // 3GAMMA FUNCTION DISABLE
    uint8_t gamma_disable[1] = {0x00};
    Send_Command(0xF2, gamma_disable, 1, hspi2);

    // GAMMA CURVE SELECT
    uint8_t gamma_curve[1] = {0x01};
    Send_Command(0x26, gamma_curve, 1, hspi2);

    // POSITIVE GAMMA CORRECTION
    uint8_t pgamma[15] = {
        0x0F, 0x31, 0x2B, 0x0C, 0x0E,
        0x08, 0x4E, 0xF1, 0x37, 0x07,
        0x10, 0x03, 0x0E, 0x09, 0x00
    };
    Send_Command(0xE0, pgamma, 15, hspi2);

    // NEGATIVE GAMMA CORRECTION
    uint8_t ngamma[15] = {
        0x00, 0x0E, 0x14, 0x03, 0x11,
        0x07, 0x31, 0xC1, 0x48, 0x08,
        0x0F, 0x0C, 0x31, 0x36, 0x0F
    };
    Send_Command(0xE1, ngamma, 15, hspi2);

    // EXIT SLEEP
    Send_Command_NoArgs(0x11, hspi2);
    HAL_Delay(120);

    // DISPLAY ON
    Send_Command_NoArgs(0x29, hspi2);
}

void clean_screen(uint16_t color, SPI_HandleTypeDef *hspi2) {
	Write_Rectangle(
	        0,                      // row_lower
	        ILI9341_HEIGHT - 1,     // row_higher
	        0,                      // col_lower
	        ILI9341_WIDTH - 1,      // col_higher
	        color,
	        hspi2
	    );
}

 The main

int main(void)
{

  /* USER CODE BEGIN 1 */


  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_I2S3_Init();
  MX_SPI1_Init();
  MX_USB_HOST_Init();
  MX_SPI2_Init();
  MX_TIM2_Init();
  /* USER CODE BEGIN 2 */
  //Reset the screen
  ILI9341_Init(&hspi2);
  //screen experiment, delete later (black rectangle)
  HAL_Delay(1000);

  //Write_Rectangle(0, 50, 0, 50, 0, &hspi2); //good
  //draw_digit(10, 10, 12, 8, 0, &hspi2); //good
  //draw_number(UINT32_MAX, 12, &hspi2); //good
  draw_ready = 1;

  //Set everything for the accelometer
  uint8_t OUT_X_L = 0x28;
  uint8_t OUT_X_H = 0x29;
  uint8_t OUT_Y_L = 0x2A;
  uint8_t OUT_Y_H = 0x2B;
  uint8_t OUT_Z_L = 0x2C;
  uint8_t OUT_Z_H = 0x2D;
  uint8_t CTRL_REG5 = 0x24; //for sensitivity (change from default 2 to 4/8) (bits 5-4)
  //receivers and transmitters
  xyz_addr[0] = OUT_X_L; xyz_addr[1] = OUT_X_H; xyz_addr[2] = OUT_Y_L; xyz_addr[3] = OUT_Y_H; xyz_addr[4] = OUT_Z_L; xyz_addr[5] = OUT_Z_H;
  uint8_t ctrl_val;

  //fill buffer with 0s
  for (int i = 0; i < ACC_BUF_SIZE; i++) {
	  acc_values_buf[i] = 0;
  }

  //receive and set accelerator sensitivity
  //HAL_SPI_TransmitReceive(&hspi1, &CTRL_REG5, &ctrl_val, 1, 100);
  //ctrl_val =  ctrl_val | 0x08; //set FSCALE0
  //uint8_t tx_buf[2];
  //tx_buf[0] = CTRL_REG5 & 0x7F; //register address
  //tx_buf[1] = ctrl_val; //data to write into it
  //HAL_SPI_Transmit(&hspi1, tx_buf, 1, 100);

  //initial dma call (deprecated)
  //HAL_SPI_TransmitReceive_DMA(&hspi1, xyz_addr, xyz_data, 6);
  //default value
  //clean_screen(0xFF, &hspi2);
  //draw_number(steps_count, 12, &hspi2);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    /* USER CODE END WHILE */
    MX_USB_HOST_Process();

    /* USER CODE BEGIN 3 */
    //During each SPI clock cycle, full-duplex transmission of a single bit occurs.
    //1 clock cycle is 168/32MHz = 5.25MHz
    //meaning there are 5.25 * 10^6 bit, or 5.25 * 10^6/8 bytes = 656250 bytes
    //or, all coordinates are received 109375 times.

  }
  /* USER CODE END 3 */
}

 

1 REPLY 1
mƎALLEm
ST Employee

Hello,

What do you mean by they fail here: "But when I call them from the interrupt handler, they fail". 

You need to describe the symptoms: it doesn't display anything? it diplays rubbish characters? 

What did you do to debug the issue apart from calling the display APIs outside the Timer interrupt callback?

Meanwhile, draw_number(steps_count, 12, &hspi2); should complete its execution in less time than the timer period.

 

 

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.