Page 1 of 1

STM32F4-Discovery ST7565 Driver

Posted: Wed Mar 19, 2014 8:29 pm
by wang701
Hi all, I am pretty new to ChibiOS and I want to write an driver for ST7565 controller.

I have pre-existing C code for initialization and drawing characters on the LCD without using ChibiOS but want to implement this driver with ChibiOS.

Here is the code for main.c:

Code: Select all

/*
    ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "ch.h"
#include "hal.h"
#include "ST7565.h"

/*
 * This is a periodic thread that does absolutely nothing except flashing
 * a LED.
 */
static WORKING_AREA(waThread1, 128);
static msg_t Thread1(void *arg) {

  (void)arg;
  chRegSetThreadName("blinker");
  while (TRUE) {
    palSetPad(GPIOD, GPIOD_LED3);       /* Orange.  */
    chThdSleepMilliseconds(500);
    palClearPad(GPIOD, GPIOD_LED3);     /* Orange.  */
    chThdSleepMilliseconds(500);
  }
}

static WORKING_AREA(spi_thread_1_wa, 256);
static msg_t spi_thread_1(void *p) {

  (void)p;
  chRegSetThreadName("blinker 2");
  while (TRUE) {
   
         palSetPad(GPIOD, GPIOD_LED5);
         chThdSleepMilliseconds(500);
         palClearPad(GPIOD, GPIOD_LED5);
         chThdSleepMilliseconds(500);
  }
}

/*
 * Application entry point.
 */
int main(void) {

  /*
   * System initializations.
   * - HAL initialization, this also initializes the configured device drivers
   *   and performs the board-specific initializations.
   * - Kernel initialization, the main() function becomes a thread and the
   *   RTOS is active.
   */
      halInit();
      chSysInit();

  /*
   * Initializes the SPI driver 2. The SPI2 signals are routed as follow:
   * PB12 - NSS.
   * PB13 - SCK.
   * PB14 - MISO.
   * PB15 - MOSI.
   */
      palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(5) |
                                             PAL_STM32_OSPEED_HIGHEST);       /* New SCK.     */
      palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(5) |
                                          PAL_STM32_OSPEED_HIGHEST);       /* New MISO.    */
      palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(5) |
                                          PAL_STM32_OSPEED_HIGHEST);       /* New MOSI.    */
      palSetPadMode(GPIOB, 12, PAL_MODE_OUTPUT_PUSHPULL |
                                          PAL_STM32_OSPEED_HIGHEST);       /* New CS.      */
      palSetPadMode(GPIOE, 8, PAL_MODE_OUTPUT_PUSHPULL |
                                          PAL_STM32_OSPEED_HIGHEST);       /* New A0.      */
      palSetPadMode(GPIOE, 9, PAL_MODE_OUTPUT_PUSHPULL |
                                          PAL_STM32_OSPEED_HIGHEST);       /* New RES.      */
      palClearPad(GPIOE, 12);
      palClearPad(GPIOE, 8);
      palClearPad(GPIOE, 9);   
      
      LcdInit();
      //chThdSleep(1000);
     Clear();
                        
//      disp_str("SKYWAVE VER 1.0",0,0);
//      disp_str("STATUS:",0,2);
//      disp_str("CONNECTED",75,2);
//      disp_str("STRENGTH:",0,3);
//      disp_str("*********",75,3);
//      disp_str("TITLE:",0,4);
//      disp_str("HEY JUDE",75,4);
//      disp_str("PLAYTIME:",0,5);
//      disp_str("5:32",75,5);
//      disp_str("SETTING:",0,6);
//      disp_str("ROCK",75,6);
//      disp_str("VOLUME:",0,7);
//      disp_str("30",115,7);
  /*
   * Creates the example thread.
   */
  chThdCreateStatic(waThread1, sizeof(waThread1), NORMALPRIO, Thread1, NULL);
   chThdCreateStatic(spi_thread_1_wa, sizeof(spi_thread_1_wa), NORMALPRIO + 1, spi_thread_1, NULL);

  /*
   * Normal main() thread activity, in this demo it does nothing except
   * sleeping in a loop and check the button state, when the button is
   * pressed the test procedure is launched with output on the serial
   * driver 2.
   */
  while (TRUE) {

  }
}


And here is the code which contains several functions like clearing the screen and printing character:

Code: Select all

#include "ch.h"
#include "hal.h"
#include "ST7565.h"

static uint8_t lcdinit[16] = {0xe2, 0xa0, 0xc8, 0x2f, 0x27, 0xaf, 0x40, 0xc8, 0xa6, 0xa4, 0xa3, 0x81, 0x0, 0xf8, 0x3, 0xa5};
static uint8_t lcdcmd[1] = {0};
static uint8_t lcddat[1] = {0};


//static void spicb(SPIDriver *spip);

///*
// * SPI end transfer callback.
// */
//static void spicb(SPIDriver *spip) {

//  /* On transfer end just releases the slave select line.*/
//  chSysLockFromIsr();
//  spiUnselectI(spip);
//  chSysUnlockFromIsr();
//}

static const SPIConfig spicfg = {
  NULL,
  /* HW dependent part.*/
  GPIOB,
  12,
  SPI_CR1_BR_0 | SPI_CR1_BR_1 | SPI_CR1_CPOL | SPI_CR1_CPHA
};


unsigned char CurOffset;

#define ASC_CHR_WIDTH   5
#define ASC_CHR_HEIGHT 12
#define ASC_HZ_WIDTH   16


typedef struct
{
    char Index[1];
    char Msk[5];
}typFNT_ASC16;

const  typFNT_ASC16  ASC_16[] =
{
   "*",0x14, 0x08, 0x3E, 0x08, 0x14,
   ".",0x60, 0x60, 0x00, 0x00, 0x00,
   ":",0x00, 0x00, 0x24, 0x00, 0x00,
   " ",0x00, 0x00, 0x00, 0x00, 0x00,
   "0",0x3e, 0x41, 0x41, 0x41, 0x3e,
   "1",0x00, 0x42, 0x7F, 0x40, 0x00,
   "2",0x71, 0x49, 0x49, 0x49, 0x46,
   "3",0x41, 0x49, 0x49, 0x49, 0x36,
  "4",0x1C, 0x12, 0x11, 0x7F, 0x10,
  "5",0x4F, 0x49, 0x49, 0x49, 0x31,
  "6",0x3E, 0x49, 0x49, 0x49, 0x30,
  "7",0x01, 0x71, 0x09, 0x05, 0x03,
  "8",0x36, 0x49, 0x49, 0x49, 0x36,
  "9",0x06, 0x49, 0x49, 0x49, 0x3E,
   "A",0x78, 0x16, 0x11, 0x16, 0x78,
   "B",0x7f, 0x49, 0x49, 0x49, 0x36,
   "C",0x3e, 0x41, 0x41, 0x41, 0x41,
   "D",0x7f, 0x41, 0x41, 0x41, 0x3E,
   "E",0x7f, 0x49, 0x49, 0x49, 0x41,
   "F",0x7f, 0x09, 0x09, 0x09, 0x01,
   "G",0x3e, 0x41, 0x49, 0x49, 0x79,
   "H",0x7f, 0x08, 0x08, 0x08, 0x7f,
   "I",0x00, 0x00, 0x7f, 0x00, 0x00,
   "J",0x20, 0x40, 0x40, 0x3f, 0x00,
   "K",0x7f, 0x08, 0x14, 0x22, 0x41,
   "L",0x7f, 0x40, 0x40, 0x40, 0x40,
   "M",0x7f, 0x06, 0x18, 0x06, 0x7f,
   "N",0x7f, 0x06, 0x08, 0x30, 0x7f,
   "O",0x3e, 0x41, 0x41, 0x41, 0x3e,
   "P",0x7f, 0x09, 0x09, 0x09, 0x06,
   "Q",0x3e, 0x41, 0x41, 0x21, 0x5e,
   "R",0x7f, 0x09, 0x19, 0x29, 0x46,
   "S",0x46, 0x49, 0x49, 0x49, 0x31,
   "T",0x01, 0x01, 0x7f, 0x01, 0x01,
   "U",0x3f, 0x40, 0x40, 0x40, 0x3f,
   "V",0x07, 0x38, 0x40, 0x38, 0x07,
   "W",0x3f, 0x40, 0x3c, 0x40, 0x3f,
   "X",0x63, 0x14, 0x08, 0x14, 0x63,
   "Y",0x03, 0x04, 0x78, 0x04, 0x03,
   "Z",0x61, 0x51, 0x49, 0x45, 0x43
};
   
void Comwrite(u8 cmd)
{         
       Reset_A0;      //A0=0;
         spiAcquireBus(&SPID2);              /* Acquire ownership of the bus.    */
      spiStart(&SPID2, &spicfg);       /* Setup transfer parameters.       */
      spiSelect(&SPID2);                  /* Slave Select assertion.          */
         //Reset_CS;      
         lcdcmd[0] = cmd;
      spiSend(&SPID2, 1, lcdcmd);          /* Atomic transfer operations.      */
         //spiUnselect(&SPID2);
       //Set_CS;
      spiReleaseBus(&SPID2);              /* Ownership release.               */
}


void Datwrite(u8 dat)   
{                     
         Reset_A0;      //A0=0;
         spiAcquireBus(&SPID2);              /* Acquire ownership of the bus.    */
      spiStart(&SPID2, &spicfg);       /* Setup transfer parameters.       */
         Set_A0;            //A0=1;   
      spiSelect(&SPID2);                  /* Slave Select assertion.          */
         //Reset_CS;
         lcddat[0] = dat;
      spiSend(&SPID2, 1, lcddat);          /* Atomic transfer operations.      */
         //spiUnselect(&SPID2);
         //Set_CS;
      spiReleaseBus(&SPID2);              /* Ownership release.               */

}

void Clear(void)
{   
    u8  i,j;
   for(i=0;i<8;i++)   
    {
         Setadd(0,i);          
     for(j=0;j<128;j++)
       Datwrite(0x00);
     }

}

void Setadd(u8 xl,u8 yl)
{
   u8 i;
  xl+=0;
  i=(xl+0)&0x0f;
  xl=(xl>>4)+0x10;

  Comwrite(0xb0+yl);     
   Comwrite(xl);
    Comwrite(i);   
}


void LcdInit(void)
{   
      Reset_RES;
      chThdSleepMilliseconds(50);
      Set_RES;
   
      Reset_A0;      //A0=0;
      spiAcquireBus(&SPID2);              /* Acquire ownership of the bus.    */
      spiStart(&SPID2, &spicfg);       /* Setup transfer parameters.       */
      spiSelect(&SPID2);         
    spiSend(&SPID2, 16, lcdinit);          /* Atomic transfer operations.      */
      //spiUnselect(&SPID2);
    spiReleaseBus(&SPID2);              /* Ownership release.               */
}

void disp_ch(unsigned char c,u8 uCol,u8 uPage)
{
   unsigned char k,j,ch_w;
   unsigned char width;
   unsigned char len;

   len=sizeof(ASC_16)/sizeof(ASC_16[0]);
   for(k=0;k<len;k++)
   {
      if(c == ASC_16[k].Index[0] ) break;
   }
   if(k<len)
   {
      
      if(c=='-'||c==':')
         width=ASC_CHR_WIDTH-2;
      else if(c=='|')
         width=ASC_HZ_WIDTH-ASC_CHR_WIDTH;
      else
         width=ASC_CHR_WIDTH;
      
         Setadd(uCol,uPage);
         for(j=0;j<width;j++)
         {
            ch_w=ASC_16[k].Msk[j];            
            Datwrite(ch_w);
         }
   }
}

void disp_str(u8 *p,u8 uCol,u8 uPage)
{
   unsigned char i=0;
   while(p[i]>0)
   {
      if(p[i] < 128)
      {   
         disp_ch(p[i],uCol,uPage);
            uCol+=6;   // 6 depends on character width
      }
      i++;
   }
}



The problem is that I could initialize the screen without problem. Notice the 0xa5 in lcdinit variable which will turn all dots on. The LCD will do that without problem.

However, I cannot get other functions to work right with ChibiOS. For instance, I couldn't using Clear() to clear the dots on screen. My suspicion is the Setadd() function which sets the XY coordinate actually causes some problem but I don't know how to modify it since it's already working without ChibiOS.

Advice needed. Thank you!

Re: STM32F4-Discovery ST7565 Driver

Posted: Wed Mar 19, 2014 9:22 pm
by wang701
I discovered the problem.

The clearing and drawing functions are correct; it's the 0xa5 command that caused the every dots to be turned on constantly. Even though the Clear() function is applied.

By getting rid of the 0xa5 value, the LCD displays the characters quite well.

Re: STM32F4-Discovery ST7565 Driver

Posted: Thu Mar 20, 2014 9:05 am
by Giovanni
OK :)

Giovanni