Working initialisation on LCD

+ lcd driver
+ lcd doc (HD44780)
This commit is contained in:
Steins7 2020-01-26 16:59:04 +01:00
parent 46cc635d31
commit 45fde375b8
4 changed files with 204 additions and 137 deletions

BIN
docs/HD44780.pdf Normal file

Binary file not shown.

127
src/drivers/lcd.c Normal file
View File

@ -0,0 +1,127 @@
#include "lcd.h"
enum mode {
WRITE,
READ,
UNDEFINED
};
static int mode = UNDEFINED;
//------------------------------------------------------------------------------
// internal functions
int set_mode_read(void) {
// configure pins
if(io_configure(GPIOA, PIN_8 | PIN_12 | PIN_15, IO_MODE_INPUT |
IO_IN_FLOATING, 0)) return -1;
if(io_configure(GPIOB, PIN_3 | PIN_4 | PIN_13 | PIN_14 | PIN_15,
IO_MODE_INPUT | IO_IN_FLOATING, 0)) return -1;
// put lcd in read mode
io_set(GPIOA, PIN_9); // after the pins are ready to recieve voltage
mode = READ;
return 0;
}
int set_mode_write(void) {
// put lcd in write mode
io_clear(GPIOA, PIN_9); //before the pin can send voltage
// configure pins
if(io_configure(GPIOA, PIN_8 | PIN_12 | PIN_15, IO_MODE_OUTPUT |
IO_OUT_PUSH_PULL, 0)) return -1;
if(io_configure(GPIOB, PIN_3 | PIN_4 | PIN_13 | PIN_14 | PIN_15,
IO_MODE_OUTPUT | IO_OUT_PUSH_PULL, 0)) return -1;
mode = WRITE;
return 0;
}
void wait_for_ready(void) {
// configure the lcd
if(mode != READ) if(set_mode_read()) return;
// read D7 pin
for(;;) {
io_set(GPIOA, PIN_11);
for(int i=0; i<1000; ++i); //timer_wait is overkill here
if(!io_read(GPIOB, PIN_4)) break;
io_clear(GPIOA, PIN_11);
for(int i=0; i<1000; ++i); //same
}
io_clear(GPIOA, PIN_11);
}
void write_byte(uint8_t byte) {
// put the lcd bus in write mode
if(mode != WRITE) if(set_mode_write()) return;
// start tranfert
io_set(GPIOA, PIN_11);
timer_wait_us(TIM1, 1, 0);
// send the data
io_write(GPIOA, (byte >> 0) & 0x1, PIN_8);
io_write(GPIOA, (byte >> 1) & 0x1, PIN_12);
io_write(GPIOB, (byte >> 2) & 0x1, PIN_15);
io_write(GPIOA, (byte >> 3) & 0x1, PIN_15);
io_write(GPIOB, (byte >> 4) & 0x1, PIN_14);
io_write(GPIOB, (byte >> 5) & 0x1, PIN_3);
io_write(GPIOB, (byte >> 6) & 0x1, PIN_13);
io_write(GPIOB, (byte >> 7) & 0x1, PIN_4);
// validate data
io_clear(GPIOA, PIN_11);
}
//------------------------------------------------------------------------------
// API functions
int lcd_init(TIM_TypeDef* tim) {
// disable JTAG, as it utilise needed pins, SWD remains usable in
// synchronous mode
RCC->APB2ENR |= 0x1;
AFIO->MAPR = (AFIO->MAPR & ~(0x8 << 24)) | 0x2 << 24;
// configure the lcd control pins
if(io_configure(GPIOA, PIN_9 | PIN_10 | PIN_11, IO_MODE_OUTPUT |
IO_OUT_PUSH_PULL, 0)) return -1;
// put the lcd bus in write mode
if(set_mode_write()) return -1; //no check in case the pins were used
//somewhere else
// select instrution register
io_write(GPIOA, LCD_MODE_CMD, PIN_10);
// begin initialisation sequence
timer_wait_ms(tim, 15, 0);
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
timer_wait_ms(tim, 5, 0);
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
timer_wait_us(tim, 150, 0);
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
wait_for_ready();
write_byte(LCD_FUNC_SET | LCD_FUNC_8BIT | LCD_FUNC_2LINE |
LCD_FUNC_5x8DOTS);
wait_for_ready();
write_byte(LCD_DISP_CTRL | LCD_CTRL_DISP_OFF | LCD_CTRL_CUR_OFF |
LCD_CTRL_BLINK_OFF);
wait_for_ready();
write_byte(LCD_CLEAR);
wait_for_ready();
write_byte(LCD_ENTRY | LCD_ENTRY_LEFT | LCD_ENTRY_SHIFT_DEC);
wait_for_ready();
// post initialisation setup
write_byte(LCD_DISP_CTRL | LCD_CTRL_DISP_ON | LCD_CTRL_CUR_ON |
LCD_CTRL_BLINK_ON);
wait_for_ready();
write_byte(LCD_CLEAR);
wait_for_ready();
return 0;
}

77
src/drivers/lcd.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef LCD_H
#define LCD_H
#include "../target/stm32f103xb.h"
#include "../config.h"
#include "timer.h"
#include "io.h"
//------------------------------------------------------------------------------
/* LCD mode selection */
enum lcd_register {
LCD_MODE_CMD = 0,
LCD_MODE_DATA = 1
};
//------------------------------------------------------------------------------
/* LCD commands */
enum lcd_command {
LCD_CLEAR = 0x01,
LCD_CR = 0x02,
LCD_ENTRY = 0x04,
LCD_DISP_CTRL = 0x08,
LCD_SHIFT = 0x10,
LCD_FUNC_SET = 0x20,
LCD_CGRAM_ADDR = 0x40,
LCD_DDRAM_ADDR = 0x80
};
//------------------------------------------------------------------------------
/* LCD_ENTRY command options */
enum lcd_entry_option {
LCD_ENTRY_RIGHT = 0x00,
LCD_ENTRY_LEFT = 0x02,
LCD_ENTRY_SHIFT_INC = 0x01,
LCD_ENTRY_SHIFT_DEC = 0x00
};
//------------------------------------------------------------------------------
/* LCD_DISP_CTRL command options */
enum lcd_ctrl_option {
LCD_CTRL_DISP_ON = 0x04,
LCD_CTRL_DISP_OFF = 0x00,
LCD_CTRL_CUR_ON = 0x02,
LCD_CTRL_CUR_OFF = 0x00,
LCD_CTRL_BLINK_ON = 0x01,
LCD_CTRL_BLINK_OFF = 0x00
};
//------------------------------------------------------------------------------
/* LCD_SHIFT command options */
enum lcd_shift_option {
LCD_SHIFT_DISP = 0x08,
LCD_SHIFT_CUR = 0x00,
LCD_SHIFT_RIGHT = 0x04,
LCD_SHIFT_LEFT = 0x00
};
//------------------------------------------------------------------------------
/* LCD_FUNC_SET command options */
enum lcd_func_option {
LCD_FUNC_8BIT = 0x10,
LCD_FUNC_4BIT = 0x00,
LCD_FUNC_2LINE = 0x08,
LCD_FUNC_1LINE = 0x00,
LCD_FUNC_5x10DOTS = 0x04,
LCD_FUNC_5x8DOTS = 0x00
};
//------------------------------------------------------------------------------
int lcd_init(TIM_TypeDef* tim);
void lcd_write(uint8_t byte);
uint8_t lcd_read(void);
#endif

View File

@ -1,137 +0,0 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
!_TAG_PROGRAM_VERSION 0.0.0 /3fdf28bc/
ADC_Data adc.h /^} ADC_Data;$/;" t typeref:struct:__anon0f12ca630108
ADC_H adc.h /^#define ADC_H$/;" d
CLOCK_CONFIG_END rcc.h /^ CLOCK_CONFIG_END$/;" e enum:Clock_config
CLOCK_CONFIG_PERFORMANCE rcc.h /^ CLOCK_CONFIG_PERFORMANCE,$/;" e enum:Clock_config
CLOCK_CONFIG_POWERSAVE rcc.h /^ CLOCK_CONFIG_POWERSAVE,$/;" e enum:Clock_config
ClockConfig_t rcc.c /^struct ClockConfig_t {$/;" s file:
Clock_config rcc.h /^enum Clock_config {$/;" g
Clock_t rcc.h /^} Clock_t;$/;" t typeref:struct:_Clock_t
EXTI0_IRQHandler io.c /^void EXTI0_IRQHandler() {$/;" f typeref:typename:void
EXTI15_10_IRQHandler io.c /^void EXTI15_10_IRQHandler() {$/;" f typeref:typename:void
EXTI1_IRQHandler io.c /^void EXTI1_IRQHandler() {$/;" f typeref:typename:void
EXTI2_IRQHandler io.c /^void EXTI2_IRQHandler() {$/;" f typeref:typename:void
EXTI3_IRQHandler io.c /^void EXTI3_IRQHandler() {$/;" f typeref:typename:void
EXTI4_IRQHandler io.c /^void EXTI4_IRQHandler() {$/;" f typeref:typename:void
EXTI9_5_IRQHandler io.c /^void EXTI9_5_IRQHandler() {$/;" f typeref:typename:void
IO_CLEAR io.h /^#define IO_CLEAR /;" d
IO_IN_ANALOG io.h /^ IO_IN_ANALOG = (0b0 << 2),$/;" e enum:io_conf
IO_IN_FLOATING io.h /^ IO_IN_FLOATING = (0b1 << 2),$/;" e enum:io_conf
IO_IN_PULL_DOWN io.h /^ IO_IN_PULL_DOWN = (0b010 << 2),$/;" e enum:io_conf
IO_IN_PULL_UP io.h /^ IO_IN_PULL_UP = (0b110 << 2),$/;" e enum:io_conf
IO_MODE_INPUT io.h /^ IO_MODE_INPUT = (0x0),$/;" e enum:io_mode
IO_MODE_OUTPUT_FAST io.h /^ IO_MODE_OUTPUT_FAST = (0x4) \/\/ 50 MHz max$/;" e enum:io_mode
IO_MODE_OUTPUT_SLOW io.h /^ IO_MODE_OUTPUT_SLOW = (0x3), \/\/ 2MHz max$/;" e enum:io_mode
IO_MODE_OUTPUT io.h /^ IO_MODE_OUTPUT = (0x1), \/\/ 10Mhz max$/;" e enum:io_mode
IO_OUT_ALT_FNCT io.h /^ IO_OUT_ALT_FNCT = (0b10 << 2),$/;" e enum:io_conf
IO_OUT_OPEN_DRAIN io.h /^ IO_OUT_OPEN_DRAIN = (0b1 << 2)$/;" e enum:io_conf
IO_OUT_PUSH_PULL io.h /^ IO_OUT_PUSH_PULL = (0b0 << 2),$/;" e enum:io_conf
OnIO io.h /^typedef void (*OnIO)();$/;" t typeref:typename:void (*)()
OnTick timer.h /^typedef void (*OnTick)(void);$/;" t typeref:typename:void (*)(void)
PIN_0 io.h /^ PIN_0 = (1 << 0),$/;" e enum:io_pin
PIN_10 io.h /^ PIN_10 = (1 << 10),$/;" e enum:io_pin
PIN_11 io.h /^ PIN_11 = (1 << 11),$/;" e enum:io_pin
PIN_12 io.h /^ PIN_12 = (1 << 12),$/;" e enum:io_pin
PIN_13 io.h /^ PIN_13 = (1 << 13),$/;" e enum:io_pin
PIN_14 io.h /^ PIN_14 = (1 << 14),$/;" e enum:io_pin
PIN_15 io.h /^ PIN_15 = (1 << 15),$/;" e enum:io_pin
PIN_1 io.h /^ PIN_1 = (1 << 1),$/;" e enum:io_pin
PIN_2 io.h /^ PIN_2 = (1 << 2),$/;" e enum:io_pin
PIN_3 io.h /^ PIN_3 = (1 << 3),$/;" e enum:io_pin
PIN_4 io.h /^ PIN_4 = (1 << 4),$/;" e enum:io_pin
PIN_5 io.h /^ PIN_5 = (1 << 5),$/;" e enum:io_pin
PIN_6 io.h /^ PIN_6 = (1 << 6),$/;" e enum:io_pin
PIN_7 io.h /^ PIN_7 = (1 << 7),$/;" e enum:io_pin
PIN_8 io.h /^ PIN_8 = (1 << 8),$/;" e enum:io_pin
PIN_9 io.h /^ PIN_9 = (1 << 9),$/;" e enum:io_pin
PIN_ALL io.h /^ PIN_ALL = 0xFFFF$/;" e enum:io_pin
RCC_CFGR_ADCPRE_DIV_2 rcc.c /^#define RCC_CFGR_ADCPRE_DIV_2 /;" d file:
RCC_CFGR_ADCPRE_DIV_4 rcc.c /^#define RCC_CFGR_ADCPRE_DIV_4 /;" d file:
RCC_CFGR_ADCPRE_DIV_6 rcc.c /^#define RCC_CFGR_ADCPRE_DIV_6 /;" d file:
RCC_CFGR_ADCPRE_DIV_8 rcc.c /^#define RCC_CFGR_ADCPRE_DIV_8 /;" d file:
RCC_CFGR_HPRE_DIV_128 rcc.c /^#define RCC_CFGR_HPRE_DIV_128 /;" d file:
RCC_CFGR_HPRE_DIV_16 rcc.c /^#define RCC_CFGR_HPRE_DIV_16 /;" d file:
RCC_CFGR_HPRE_DIV_256 rcc.c /^#define RCC_CFGR_HPRE_DIV_256 /;" d file:
RCC_CFGR_HPRE_DIV_2 rcc.c /^#define RCC_CFGR_HPRE_DIV_2 /;" d file:
RCC_CFGR_HPRE_DIV_4 rcc.c /^#define RCC_CFGR_HPRE_DIV_4 /;" d file:
RCC_CFGR_HPRE_DIV_512 rcc.c /^#define RCC_CFGR_HPRE_DIV_512 /;" d file:
RCC_CFGR_HPRE_DIV_64 rcc.c /^#define RCC_CFGR_HPRE_DIV_64 /;" d file:
RCC_CFGR_HPRE_DIV_8 rcc.c /^#define RCC_CFGR_HPRE_DIV_8 /;" d file:
RCC_CFGR_HPRE_DIV_NONE rcc.c /^#define RCC_CFGR_HPRE_DIV_NONE /;" d file:
RCC_CFGR_PLLMUL rcc.c /^#define RCC_CFGR_PLLMUL(/;" d file:
RCC_CFGR_PPRE_DIV_16 rcc.c /^#define RCC_CFGR_PPRE_DIV_16 /;" d file:
RCC_CFGR_PPRE_DIV_2 rcc.c /^#define RCC_CFGR_PPRE_DIV_2 /;" d file:
RCC_CFGR_PPRE_DIV_4 rcc.c /^#define RCC_CFGR_PPRE_DIV_4 /;" d file:
RCC_CFGR_PPRE_DIV_8 rcc.c /^#define RCC_CFGR_PPRE_DIV_8 /;" d file:
RCC_CFGR_PPRE_DIV_NONE rcc.c /^#define RCC_CFGR_PPRE_DIV_NONE /;" d file:
RCC_HSE rcc.c /^ RCC_HSE,$/;" e enum:rcc_osc file:
RCC_HSI rcc.c /^ RCC_HSI,$/;" e enum:rcc_osc file:
RCC_LSE rcc.c /^ RCC_LSE$/;" e enum:rcc_osc file:
RCC_LSI rcc.c /^ RCC_LSI,$/;" e enum:rcc_osc file:
RCC_PLL rcc.c /^ RCC_PLL,$/;" e enum:rcc_osc file:
SYSCFG_EXTI_PA_MASK io.c /^#define SYSCFG_EXTI_PA_MASK /;" d file:
SYSCFG_EXTI_PB_MASK io.c /^#define SYSCFG_EXTI_PB_MASK /;" d file:
SYSCFG_EXTI_PC_MASK io.c /^#define SYSCFG_EXTI_PC_MASK /;" d file:
SYSCFG_EXTI_PD_MASK io.c /^#define SYSCFG_EXTI_PD_MASK /;" d file:
SYSCFG_EXTI_PE_MASK io.c /^#define SYSCFG_EXTI_PE_MASK /;" d file:
SYSCFG_EXTI_PH_MASK io.c /^#define SYSCFG_EXTI_PH_MASK /;" d file:
TIM1_UP_IRQHandler timer.c /^void TIM1_UP_IRQHandler(void) {$/;" f typeref:typename:void
TIM2_IRQHandler timer.c /^void TIM2_IRQHandler(void) {$/;" f typeref:typename:void
TIM3_IRQHandler timer.c /^void TIM3_IRQHandler(void) {$/;" f typeref:typename:void
TIM4_IRQHandler timer.c /^void TIM4_IRQHandler(void) {$/;" f typeref:typename:void
TIMER_H timer.h /^#define TIMER_H$/;" d
_Clock_t rcc.h /^typedef struct _Clock_t {$/;" s
_IO_H_ io.h /^#define _IO_H_$/;" d
_RCC_H_ rcc.h /^#define _RCC_H_$/;" d
__anon0f12ca630108 adc.h /^typedef struct {$/;" s
_clock_config rcc.c /^static struct ClockConfig_t _clock_config[] = {$/;" v typeref:struct:ClockConfig_t[] file:
adc_init adc.c /^int adc_init(ADC_TypeDef* adc) {$/;" f typeref:typename:int
adc_read adc.c /^int adc_read(void) {$/;" f typeref:typename:int
adcpre rcc.c /^ uint8_t adcpre;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file:
ahb_freq rcc.c /^ uint32_t ahb_freq;$/;" m struct:ClockConfig_t typeref:typename:uint32_t file:
ahb_freq rcc.h /^ uint32_t ahb_freq;$/;" m struct:_Clock_t typeref:typename:uint32_t
apb1_freq rcc.c /^ uint32_t apb1_freq;$/;" m struct:ClockConfig_t typeref:typename:uint32_t file:
apb1_freq rcc.h /^ uint32_t apb1_freq;$/;" m struct:_Clock_t typeref:typename:uint32_t
apb1_timer_freq rcc.h /^ uint32_t apb1_timer_freq;$/;" m struct:_Clock_t typeref:typename:uint32_t
apb2_freq rcc.c /^ uint32_t apb2_freq;$/;" m struct:ClockConfig_t typeref:typename:uint32_t file:
apb2_freq rcc.h /^ uint32_t apb2_freq;$/;" m struct:_Clock_t typeref:typename:uint32_t
apb2_timer_freq rcc.h /^ uint32_t apb2_timer_freq;$/;" m struct:_Clock_t typeref:typename:uint32_t
callback1 timer.c /^static OnTick callback1 = 0;$/;" v typeref:typename:OnTick file:
callback2 timer.c /^static OnTick callback2 = 0;$/;" v typeref:typename:OnTick file:
callback3 timer.c /^static OnTick callback3 = 0;$/;" v typeref:typename:OnTick file:
callback4 timer.c /^static OnTick callback4 = 0;$/;" v typeref:typename:OnTick file:
flash_cfg rcc.c /^ uint32_t flash_cfg;$/;" m struct:ClockConfig_t typeref:typename:uint32_t file:
hpre rcc.c /^ uint8_t hpre;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file:
io_cb io.c /^static OnIO io_cb[16]={$/;" v typeref:typename:OnIO[16] file:
io_clear io.c /^void io_clear(GPIO_TypeDef *gpio, uint16_t mask)$/;" f typeref:typename:void
io_conf io.h /^enum io_conf {$/;" g
io_configure io.c /^int io_configure(GPIO_TypeDef *gpio, uint16_t pin, uint8_t pin_cfg, OnIO cb) {$/;" f typeref:typename:int
io_mode io.h /^enum io_mode {$/;" g
io_pin io.h /^enum io_pin {$/;" g
io_read io.c /^uint32_t io_read(GPIO_TypeDef *gpio, uint16_t mask)$/;" f typeref:typename:uint32_t
io_set io.c /^void io_set(GPIO_TypeDef *gpio, uint16_t mask)$/;" f typeref:typename:void
io_write_n io.c /^void io_write_n(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask)$/;" f typeref:typename:void
io_write io.c /^void io_write(GPIO_TypeDef *gpio, uint16_t val, uint16_t mask)$/;" f typeref:typename:void
pll_src rcc.c /^ uint8_t pll_src;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file:
pllmul rcc.c /^ uint8_t pllmul;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file:
ppre1 rcc.c /^ uint8_t ppre1;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file:
ppre2 rcc.c /^ uint8_t ppre2;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file:
rcc_config_clock rcc.c /^void rcc_config_clock(uint32_t config, Clock_t *sysclks)$/;" f typeref:typename:void
rcc_osc_off rcc.c /^static void rcc_osc_off(enum rcc_osc osc)$/;" f typeref:typename:void file:
rcc_osc_on rcc.c /^static void rcc_osc_on(enum rcc_osc osc)$/;" f typeref:typename:void file:
rcc_osc rcc.c /^enum rcc_osc {$/;" g file:
rcc_set_sysclk rcc.c /^static void rcc_set_sysclk(enum rcc_osc osc)$/;" f typeref:typename:void file:
timer_config_cb timer.c /^int timer_config_cb(TIM_TypeDef* tmr, uint32_t* clk, OnTick cb) {$/;" f typeref:typename:int
timer_set_period timer.c /^int timer_set_period(TIM_TypeDef *tmr, uint16_t tick) {$/;" f typeref:typename:int
timer_start timer.c /^void timer_start(TIM_TypeDef *tmr) {$/;" f typeref:typename:void
timer_stop timer.c /^void timer_stop(TIM_TypeDef *tmr) {$/;" f typeref:typename:void
timer_tick_init timer.c /^int timer_tick_init(TIM_TypeDef *tmr, uint16_t tick_ms, OnTick cb) {$/;" f typeref:typename:int
timer_wait_ms timer.c /^int timer_wait_ms(TIM_TypeDef* tmr, uint16_t ms, OnTick cb) {$/;" f typeref:typename:int
timer_wait_us timer.c /^int timer_wait_us(TIM_TypeDef* tmr, uint16_t us, OnTick cb) {$/;" f typeref:typename:int
type rcc.c /^ uint8_t type;$/;" m struct:ClockConfig_t typeref:typename:uint8_t file: