beginTransaction problem with Arduino Nicla Vision

Hi everyone !

I am trying to connect a round 1.28" LCD device (from Waveshare) to the brand new Arduino Nicla Vision (based on an STM32H7). I also want to add a MCP2515 (CAN) on the SPI (but it's for later)

I try several solutions :

  • The "stock" solution from Arduino_GFX wasn't working with the nicla vision (no problem with an arduino nano to test the LCD).
  • I got an example working with the nicla using micropython, but it's very slow and openMV is more limited with libraries than ArduinoIDE.
  • So I try to modify the C code by Waveshare. I placed serial's flags to identify the problem.

I would like to keep the SPI.beginTransaction(...) function to modify the SPI parameters between the MCP2515 and the LCD.

  • If I use the SPI.beginTransaction(...) function : I got an infinite loop in the SPI.beginTransaction(...) function.
  • If I use the SPI.begin() function : I got an infinite loop in the SPI.transfer(...) function.

I post a zip with the 7 files used in the project.
This is a core extract of the LCD initialisation function.

Is someone has more knowledge than me on this type of device, thank you for your help :pray:. To understand why the program seems crash without any explanation !!!? :thinking:
The hardware setup seems correct because it work on micropython. So it seems a SPI software problem.

LCD_1inch28_2.zip (22,9 Ko)

#include "LCD_Driver.h"
#include <SPI.h>

SPISettings LCD_SPI_settings(1000000, MSBFIRST, SPI_MODE3); 
#define LCD_SPI_WRITE   SPI.transfer 
#define LCD_SPI_BEGIN() SPI.beginTransaction(LCD_SPI_settings) //SPI.beginTransaction(LCD_SPI_settings(10000000, MSBFIRST, SPI_MODE3))
#define LCD_SPI_END()   SPI.endTransaction()

#define LCD_SELECT()  digitalWrite(LCD_CS_PIN, LOW)
#define LCD_UNSELECT()  digitalWrite(LCD_CS_PIN, HIGH)
#define LCD_COMMAND() digitalWrite(LCD_CS_PIN, LOW)
#define LCD_UNCOMMAND() digitalWrite(LCD_DC_PIN, HIGH)
#define LCD_RST_ON()  digitalWrite(LCD_RST_PIN, LOW)
#define LCD_RST_OFF() digitalWrite(LCD_RST_PIN, HIGH)

void LCD_WriteData_Byte(uint8_t da) { 
  LCD_SPI_BEGIN();
  LCD_SELECT();
  LCD_UNCOMMAND();
  LCD_SPI_WRITE(da);
  LCD_UNSELECT();
  LCD_SPI_END();
}  

 void LCD_WriteData_Word(uint16_t da) {
 // uint8_t i = (da >> 8) & 0xff;
  LCD_SPI_BEGIN();
  LCD_SELECT();
  LCD_UNCOMMAND();
  LCD_SPI_WRITE(da>>8);
  LCD_SPI_WRITE(da);
  LCD_UNSELECT();
  LCD_SPI_END();
}   

void LCD_WriteReg(uint8_t da) {  
  LCD_SPI_BEGIN();
  Serial.println("Begin OK");
  LCD_SELECT();
  Serial.println("Select OK");
  LCD_COMMAND();
  Serial.println("Command OK");
  LCD_SPI_WRITE(da);
  Serial.println("Write OK");
  LCD_UNSELECT();
  Serial.println("Unselect OK");
  LCD_SPI_END();
}

void LCD_Init(void) {
  //Déclaration des pins
  pinMode(LCD_CS_PIN, OUTPUT);
  pinMode(LCD_RST_PIN, OUTPUT);
  pinMode(LCD_DC_PIN, OUTPUT);
  pinMode(LCD_BL_PIN, OUTPUT);
  
  //Serial
  Serial.begin(115200);
  delay(1000);
  Serial.println("Serial OK; Reset start");

  LCD_UNSELECT();
  LCD_UNCOMMAND();
  LCD_RST_ON();
  delay(10);
  LCD_RST_OFF();
  delay(10);
  Serial.println("Reset OK; Sequence start");

	LCD_WriteReg(0xEF);
        Serial.println("firt byte OK");
	LCD_WriteReg(0xEB);
	LCD_WriteData_Byte(0x14); 
	LCD_WriteReg(0xFE);			 
	LCD_WriteReg(0xEF); 
	LCD_WriteReg(0xEB);	
	LCD_WriteData_Byte(0x14); 
	LCD_WriteReg(0x84);			
	LCD_WriteData_Byte(0x40); 
	LCD_WriteReg(0x85);			
	LCD_WriteData_Byte(0xFF); 
	LCD_WriteReg(0x86);			
	LCD_WriteData_Byte(0xFF); 
	LCD_WriteReg(0x87);			
	LCD_WriteData_Byte(0xFF);
	LCD_WriteReg(0x88);			
	LCD_WriteData_Byte(0x0A);
	LCD_WriteReg(0x89);			
	LCD_WriteData_Byte(0x21); 
	LCD_WriteReg(0x8A);			
	LCD_WriteData_Byte(0x00); 
	LCD_WriteReg(0x8B);			
	LCD_WriteData_Byte(0x80); 
	LCD_WriteReg(0x8C);			
	LCD_WriteData_Byte(0x01); 
	LCD_WriteReg(0x8D);			
	LCD_WriteData_Byte(0x01); 
	LCD_WriteReg(0x8E);			
	LCD_WriteData_Byte(0xFF); 
	LCD_WriteReg(0x8F);			
	LCD_WriteData_Byte(0xFF); 
	LCD_WriteReg(0xB6);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x20);
	LCD_WriteReg(0x36);
	LCD_WriteData_Byte(0x08);
	LCD_WriteReg(0x3A);			
	LCD_WriteData_Byte(0x05); 
	LCD_WriteReg(0x90);			
	LCD_WriteData_Byte(0x08);
	LCD_WriteData_Byte(0x08);
	LCD_WriteData_Byte(0x08);
	LCD_WriteData_Byte(0x08); 
	LCD_WriteReg(0xBD);			
	LCD_WriteData_Byte(0x06);
	LCD_WriteReg(0xBC);			
	LCD_WriteData_Byte(0x00);	
	LCD_WriteReg(0xFF);			
	LCD_WriteData_Byte(0x60);
	LCD_WriteData_Byte(0x01);
	LCD_WriteData_Byte(0x04);
	LCD_WriteReg(0xC3);			
	LCD_WriteData_Byte(0x13);
	LCD_WriteReg(0xC4);			
	LCD_WriteData_Byte(0x13);
	LCD_WriteReg(0xC9);			
	LCD_WriteData_Byte(0x22);
	LCD_WriteReg(0xBE);			
	LCD_WriteData_Byte(0x11); 
	LCD_WriteReg(0xE1);			
	LCD_WriteData_Byte(0x10);
	LCD_WriteData_Byte(0x0E);
	LCD_WriteReg(0xDF);			
	LCD_WriteData_Byte(0x21);
	LCD_WriteData_Byte(0x0c);
	LCD_WriteData_Byte(0x02);
	LCD_WriteReg(0xF0);   
	LCD_WriteData_Byte(0x45);
	LCD_WriteData_Byte(0x09);
	LCD_WriteData_Byte(0x08);
	LCD_WriteData_Byte(0x08);
	LCD_WriteData_Byte(0x26);
 	LCD_WriteData_Byte(0x2A);
 	LCD_WriteReg(0xF1);    
 	LCD_WriteData_Byte(0x43);
 	LCD_WriteData_Byte(0x70);
 	LCD_WriteData_Byte(0x72);
 	LCD_WriteData_Byte(0x36);
 	LCD_WriteData_Byte(0x37);  
 	LCD_WriteData_Byte(0x6F);
 	LCD_WriteReg(0xF2);   
 	LCD_WriteData_Byte(0x45);
 	LCD_WriteData_Byte(0x09);
 	LCD_WriteData_Byte(0x08);
 	LCD_WriteData_Byte(0x08);
 	LCD_WriteData_Byte(0x26);
 	LCD_WriteData_Byte(0x2A);
 	LCD_WriteReg(0xF3);   
 	LCD_WriteData_Byte(0x43);
 	LCD_WriteData_Byte(0x70);
 	LCD_WriteData_Byte(0x72);
 	LCD_WriteData_Byte(0x36);
 	LCD_WriteData_Byte(0x37); 
 	LCD_WriteData_Byte(0x6F);
	LCD_WriteReg(0xED);	
	LCD_WriteData_Byte(0x1B); 
	LCD_WriteData_Byte(0x0B); 
	LCD_WriteReg(0xAE);			
	LCD_WriteData_Byte(0x77);
	LCD_WriteReg(0xCD);
	LCD_WriteData_Byte(0x63);		
	LCD_WriteReg(0x70);			
	LCD_WriteData_Byte(0x07);
	LCD_WriteData_Byte(0x07);
	LCD_WriteData_Byte(0x04);
	LCD_WriteData_Byte(0x0E); 
	LCD_WriteData_Byte(0x0F); 
	LCD_WriteData_Byte(0x09);
	LCD_WriteData_Byte(0x07);
	LCD_WriteData_Byte(0x08);
	LCD_WriteData_Byte(0x03);
	LCD_WriteReg(0xE8);			
	LCD_WriteData_Byte(0x34);
	LCD_WriteReg(0x62);			
	LCD_WriteData_Byte(0x18);
	LCD_WriteData_Byte(0x0D);
	LCD_WriteData_Byte(0x71);
	LCD_WriteData_Byte(0xED);
	LCD_WriteData_Byte(0x70); 
	LCD_WriteData_Byte(0x70);
	LCD_WriteData_Byte(0x18);
	LCD_WriteData_Byte(0x0F);
	LCD_WriteData_Byte(0x71);
	LCD_WriteData_Byte(0xEF);
	LCD_WriteData_Byte(0x70); 
	LCD_WriteData_Byte(0x70);
	LCD_WriteReg(0x63);			
	LCD_WriteData_Byte(0x18);
	LCD_WriteData_Byte(0x11);
	LCD_WriteData_Byte(0x71);
	LCD_WriteData_Byte(0xF1);
	LCD_WriteData_Byte(0x70); 
	LCD_WriteData_Byte(0x70);
	LCD_WriteData_Byte(0x18);
	LCD_WriteData_Byte(0x13);
	LCD_WriteData_Byte(0x71);
	LCD_WriteData_Byte(0xF3);
	LCD_WriteData_Byte(0x70); 
	LCD_WriteData_Byte(0x70);
	LCD_WriteReg(0x64);			
	LCD_WriteData_Byte(0x28);
	LCD_WriteData_Byte(0x29);
	LCD_WriteData_Byte(0xF1);
	LCD_WriteData_Byte(0x01);
	LCD_WriteData_Byte(0xF1);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x07);
	LCD_WriteReg(0x66);			
	LCD_WriteData_Byte(0x3C);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0xCD);
	LCD_WriteData_Byte(0x67);
	LCD_WriteData_Byte(0x45);
	LCD_WriteData_Byte(0x45);
	LCD_WriteData_Byte(0x10);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x00);
	LCD_WriteReg(0x67);			
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x3C);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x00);
	LCD_WriteData_Byte(0x01);
	LCD_WriteData_Byte(0x54);
	LCD_WriteData_Byte(0x10);
	LCD_WriteData_Byte(0x32);
	LCD_WriteData_Byte(0x98);
	LCD_WriteReg(0x74);			
	LCD_WriteData_Byte(0x10);	
	LCD_WriteData_Byte(0x85);	
	LCD_WriteData_Byte(0x80);
	LCD_WriteData_Byte(0x00); 
	LCD_WriteData_Byte(0x00); 
	LCD_WriteData_Byte(0x4E);
	LCD_WriteData_Byte(0x00);					
	LCD_WriteReg(0x98);			
	LCD_WriteData_Byte(0x3e);
	LCD_WriteData_Byte(0x07);
	LCD_WriteReg(0x35);	
	LCD_WriteReg(0x21);
	LCD_WriteReg(0x11);
	delay(120);
	LCD_WriteReg(0x29);
	delay(20);
  
  Serial.println("sequence end");
} 

Ok. I worked further on my problem and I managed to make it work !!! :partying_face:

I still don't really understand how to speed up the SPI using beginTransaction(). I read that it cost a lot to reload SPI settings for each pixels so I created a function that begin and end the SPI without sending data. Then all the voids that send data use SPI.begin().

Code du driver .c

#include "LCD_Driver.h"

/*********************************************
***** FONCTIONS D'ECRITURE DES REGISTRES *****
*********************************************/
void load_LCD_SPI_settings(void){
  LCD_SPI_BEGIN();
  LCD_SPI_TRANSACTION();
  SET_LCD_CS(ON);
  SET_LCD_CS(OFF);
  LCD_SPI_END();
}

void write_command_byte(UBYTE da) {
  LCD_SPI_BEGIN();
  //LCD_SPI_TRANSACTION();
  SET_LCD_CS(ON);
  SET_LCD_DC(ON);
  LCD_SPI_WRITE(da);
  SET_LCD_CS(OFF);
  SET_LCD_DC(OFF);
  LCD_SPI_END();
}

void write_data_byte(UBYTE da) { 
  //Serial.println("Start write_data_byte");
  LCD_SPI_BEGIN();
  //LCD_SPI_TRANSACTION();
  SET_LCD_CS(ON);
  SET_LCD_DC(OFF);
  LCD_SPI_WRITE(da);
  SET_LCD_CS(OFF);
  LCD_SPI_END();
  //Serial.println("End write_data_byte");
}

 void write_data_word(UWORD da) {
 // uint8_t i = (da >> 8) & 0xff;
  LCD_SPI_BEGIN();
  //LCD_SPI_TRANSACTION();
  SET_LCD_CS(ON);
  SET_LCD_DC(OFF);
  LCD_SPI_WRITE(da>>8);
  LCD_SPI_WRITE(da);
  SET_LCD_CS(OFF);
  LCD_SPI_END();
}   

void write_command(UBYTE nb, UBYTE arg1, ...) {
  va_list ap;
  va_start(ap, arg1);
  //(nb==1)?Serial.println(String(arg1, HEX)):Serial.print(String(arg1, HEX)+", ");
  write_command_byte(arg1);
  for(uint8_t i = nb-1; i>0; i--){;
    //uint8_t n = (uint8_t)va_arg(ap, int);
    write_data_byte((uint8_t)va_arg(ap, int));
    //(i==1)?Serial.println(String(n, HEX)):Serial.print(String(n, HEX)+", ");
  }
  va_end(ap);
}

/*************************************
***** PROCEDURE D'INITIALISATION *****
*************************************/

void LCD_Init(void) {
  //Déclaration des pins
  pinMode(LCD_CS_PIN, OUTPUT);
  pinMode(LCD_RST_PIN, OUTPUT);
  pinMode(LCD_DC_PIN, OUTPUT);
  pinMode(LCD_BL_PIN, OUTPUT);
  
  //Serial
  Serial.begin(115200);
  delay(1000);
  Serial.println("Serial OK; Reset start");

  //LCD_SPI_BEGIN()
  //LCD_SPI_TRANSACTION();
  SET_LCD_CS(OFF);
  SET_LCD_DC(OFF);
  SET_BACKLIGHT(OFF);

  //Reset
  SET_RESET(ON);
  delay(10);
  SET_RESET(OFF);
  delay(10);
  SET_BACKLIGHT(ON);

  load_LCD_SPI_settings();  
  Serial.println("Reset OK; Sequence start");

  //Initialisation sequence
  write_command(1, 0xEF);
  //Serial.println("firt byte OK");
  write_command(2, 0xEB, 0x14);
  write_command(1, 0xFE);
  write_command(1, 0xEF);
  write_command(2, 0xEB, 0x14);
  write_command(2, 0x84, 0x40);
  write_command(2, 0x85, 0xFF);
  write_command(2, 0x86, 0xFF);
  write_command(2, 0x87, 0xFF);
  write_command(2, 0x88, 0x0A);
  write_command(2, 0x89, 0x21);
  write_command(2, 0x8A, 0x00);
  write_command(2, 0x8B, 0x80);
  write_command(2, 0x8C, 0x01);
  write_command(2, 0x8D, 0x01);
  write_command(2, 0x8E, 0xFF);
  write_command(2, 0x8F, 0xFF);
  write_command(3, 0xB6, 0x00, 0x20);
  write_command(2, 0x36, 0x08);
  write_command(2, 0x3A, 0x05);
  write_command(5, 0x90, 0x08, 0x08, 0x08, 0x08);
  write_command(2, 0xBD, 0x06);
  write_command(2, 0xBC, 0x00);
  write_command(4, 0xFF, 0x60, 0x01, 0x04);
  write_command(2, 0xC3, 0x13);
  write_command(2, 0xC4, 0x13);
  write_command(2, 0xC9, 0x22);
  write_command(2, 0xBE, 0x11);
  write_command(3, 0xE1, 0x10, 0x0E);
  write_command(4, 0xDF, 0x21, 0x0c, 0x02);
  write_command(7, 0xF0, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A);
  write_command(7, 0xF1, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F);
  write_command(7, 0xF2, 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A);
  write_command(7, 0xF3, 0x43, 0x70, 0x72, 0x36, 0x37, 0x6F);
  write_command(3, 0xED, 0x1B, 0x0B);
  write_command(2, 0xAE, 0x77);
  write_command(2, 0xCD, 0x63);
  write_command(10, 0x70, 0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03);
  write_command(2, 0xE8, 0x34);
  write_command(13, 0x62, 0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70);
  write_command(13, 0x63, 0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70);
  write_command(8, 0x64, 0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07);
  write_command(11, 0x66, 0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00);
  write_command(11, 0x67, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98);
  write_command(8, 0x74, 0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00);
  write_command(3, 0x98, 0x3e, 0x07);
  write_command(1, 0x35);
  write_command(1, 0x21);
  write_command(1, 0x11);
  delay(120);
  write_command(1, 0x29);
  delay(20);
  Serial.println("sequence end");
} 

/************************************
***** FONCTIONS COMPLEMENTAIRES *****
*************************************/

//Set the cursor position
void LCD_SetCursor(UWORD X0, UWORD Y0, UWORD X1, UWORD Y1){ 
  write_command(5, GC9A01_CASET, 0x00, X0, 0x00, X1);
  write_command(5, GC9A01_RASET, 0x00, Y0, 0x00, Y1);
  write_command(1, GC9A01_RAMWR);
}

/*
void LCD_SetCursor(UWORD X0, UWORD Y0, UWORD X1, UWORD Y1){
  write_command(5, GC9A01_CASET, (X0>>8), X0, (X1>>8), X1);
  write_command(5, GC9A01_RASET, (Y0>>8), Y0, (Y1>>8), Y1);
  write_command(1, GC9A01_RAMWR);
}*/

//Clear screen function, refresh the screen to a certain color
void LCD_Clear(UWORD Color){
  UWORD i,j;    
  LCD_SetCursor(0,0,LCD_WIDTH-1,LCD_HEIGHT-1);
  for(i = 0; i < LCD_WIDTH; i++){
    for(j = 0; j < LCD_HEIGHT; j++){
      write_data_word(Color);
    }
  }
}

//Refresh a certain area to the same color
void LCD_ClearWindow(UWORD X0, UWORD Y0, UWORD X1, UWORD Y1, UWORD color){          
  UWORD i,j; 
  LCD_SetCursor(X0, Y0, X1-1,Y1-1);
  for(i = Y0; i <= Y1-1; i++){                                
    for(j = X0; j <= X1-1; j++){
      write_data_word(color);
    }
  }                   
}

//Set the color of an area
void LCD_SetWindowColor(UWORD X0, UWORD Y0, UWORD X1, UWORD Y1, UWORD Color){
  LCD_SetCursor(X0, Y0, X1, Y1);
  write_data_word(Color);      
}

//function: Draw a Uword
void LCD_SetUWORD(UWORD X, UWORD Y, UWORD Color){
  LCD_SetCursor(X, Y, X, Y);
  write_data_word(Color);      
} 


Code du header .h

#include <stdint.h>
#include <stdio.h>
#include <stdarg.h>
#include <SPI.h>
#include <avr/pgmspace.h>

#define ON 1
#define OFF 0

//DataType
#define UBYTE   uint8_t
#define UWORD   uint16_t
#define UDOUBLE uint32_t

//GPIO config
#define LCD_CS_PIN  PE_11
#define LCD_DC_PIN  PG_1
#define LCD_RST_PIN PA_9
#define LCD_BL_PIN  PG_12

#define LCD_WIDTH   240 //LCD width
#define LCD_HEIGHT  240 //LCD height

#define GC9A01_SWRESET 0x01
#define GC9A01_SLPIN   0x10
#define GC9A01_SLPOUT  0x11
#define GC9A01_INVOFF  0x20
#define GC9A01_INVON   0x21
#define GC9A01_DISPOFF 0x28
#define GC9A01_DISPON  0x29
#define GC9A01_CASET   0x2A
#define GC9A01_RASET   0x2B
#define GC9A01_RAMWR   0x2C
#define GC9A01_VSCRDEF 0x33
#define GC9A01_COLMOD  0x3A
#define GC9A01_MADCTL  0x36
#define GC9A01_VSCSAD  0x37

#define SET_RESET(_val)     (_val==1)?digitalWrite(LCD_RST_PIN, LOW):digitalWrite(LCD_RST_PIN, HIGH)
#define SET_LCD_CS(_val)    (_val==1)?digitalWrite(LCD_CS_PIN,  LOW):digitalWrite(LCD_CS_PIN,  HIGH)
#define SET_LCD_DC(_val)    (_val==1)?digitalWrite(LCD_DC_PIN,  LOW):digitalWrite(LCD_DC_PIN,  HIGH)
#define SET_BACKLIGHT(_val) (_val==1)?digitalWrite(LCD_DC_PIN, HIGH):digitalWrite(LCD_DC_PIN,   LOW)

#define LCD_SPI_WRITE         SPI.transfer
#define LCD_SPI_BEGIN()       SPI.begin()
#define LCD_SPI_TRANSACTION() SPI.beginTransaction(SPISettings(100000000, MSBFIRST, SPI_MODE3))
#define LCD_SPI_END()         SPI.endTransaction()

void load_LCD_SPI_settings(void);
void Config_Init();
void write_data_byte(UBYTE da); 
void write_data_word(UWORD da);
void write_command_byte(UBYTE da);
void write_command(UBYTE nb, UBYTE arg1, ...);

void LCD_SetCursor(UWORD X0, UWORD Y0, UWORD X1, UWORD Y1);
void LCD_SetUWORD(UWORD X, UWORD Y, UWORD Color);

void LCD_Init(void);
void LCD_SetBacklight(UBYTE Value);
void LCD_Clear(UWORD Color);
void LCD_ClearWindow(UWORD X0, UWORD Y0, UWORD X1, UWORD Y1, UWORD color);

It doesn' t seems to speed up the LCD. Is there a better solution ?
Thank for your help.


For people who are interrested, this is the full project :
LCD_1inch28.zip (20,9 Ko)