Make LCD code working. Add FSM for LCD in order to write it in mainloop
This commit is contained in:
		@@ -22,6 +22,9 @@
 | 
			
		||||
#include <reflow-controller/ui/lcd.h>
 | 
			
		||||
#include <reflow-controller/systick.h>
 | 
			
		||||
#include <stm-periph/clock-enable-manager.h>
 | 
			
		||||
#include <stm-periph/stm32-gpio-macros.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
static void lcd_port_clear(void)
 | 
			
		||||
{
 | 
			
		||||
@@ -42,9 +45,9 @@ static void lcd_enable(void)
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	//systick_wait_ms(10);
 | 
			
		||||
	LCD_DPORT->ODR &= ~LCD_E_MASK;
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	//systick_wait_ms(10);
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
@@ -141,6 +144,8 @@ static void lcd_command(uint8_t data)
 | 
			
		||||
// Set DD RAM Address --------- 0b1xxxxxxx  (Display Data RAM)
 | 
			
		||||
#define LCD_SET_DDADR           0x80
 | 
			
		||||
 | 
			
		||||
static char shadow_display[4][21];
 | 
			
		||||
 | 
			
		||||
void lcd_clear(void)
 | 
			
		||||
{
 | 
			
		||||
	lcd_command(LCD_CLEAR_DISPLAY);
 | 
			
		||||
@@ -153,7 +158,7 @@ void lcd_home(void)
 | 
			
		||||
	systick_wait_ms(3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_setcursor(uint8_t x, uint8_t y)
 | 
			
		||||
static uint8_t lcd_get_set_cursor_cmd(uint8_t x, uint8_t y)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t data;
 | 
			
		||||
 | 
			
		||||
@@ -179,9 +184,19 @@ void lcd_setcursor(uint8_t x, uint8_t y)
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return;                                   // für den Fall einer falschen Zeile
 | 
			
		||||
		/* In case of wrong line, assume first line */
 | 
			
		||||
		data = LCD_SET_DDADR + LCD_DDADR_LINE1;
 | 
			
		||||
		break;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_setcursor(uint8_t x, uint8_t y)
 | 
			
		||||
{
 | 
			
		||||
	uint8_t data;
 | 
			
		||||
 | 
			
		||||
	data = lcd_get_set_cursor_cmd(x, y);
 | 
			
		||||
	lcd_command(data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -191,13 +206,38 @@ void lcd_string(const char *data)
 | 
			
		||||
		lcd_data((uint8_t)*data++);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_port_init()
 | 
			
		||||
{
 | 
			
		||||
	LCD_DPORT->MODER &= MODER_DELETE(LCD_E) & MODER_DELETE(LCD_RS) & MODER_DELETE(LCD_DATA_BIT_OFFSET) &
 | 
			
		||||
			MODER_DELETE(LCD_DATA_BIT_OFFSET + 1) & MODER_DELETE(LCD_DATA_BIT_OFFSET + 2) &
 | 
			
		||||
			MODER_DELETE(LCD_DATA_BIT_OFFSET + 3);
 | 
			
		||||
 | 
			
		||||
	LCD_DPORT->MODER |= OUTPUT(LCD_E) | OUTPUT(LCD_RS) | OUTPUT(LCD_DATA_BIT_OFFSET) |
 | 
			
		||||
			OUTPUT(LCD_DATA_BIT_OFFSET + 1) | OUTPUT(LCD_DATA_BIT_OFFSET + 2) |
 | 
			
		||||
			OUTPUT(LCD_DATA_BIT_OFFSET + 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_clear_shadow_buff()
 | 
			
		||||
{
 | 
			
		||||
	int i, j;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < 4; i++) {
 | 
			
		||||
		for (j = 0; j < 21; j++) {
 | 
			
		||||
			shadow_display[i][j] = 0x0;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lcd_init(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	rcc_manager_enable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LCD_RCC_MASK));
 | 
			
		||||
	lcd_port_init();
 | 
			
		||||
	lcd_port_clear();
 | 
			
		||||
 | 
			
		||||
	lcd_clear_shadow_buff();
 | 
			
		||||
 | 
			
		||||
	systick_wait_ms(100);
 | 
			
		||||
	LCD_DPORT->ODR |= (0x3 << LCD_DATA_BIT_OFFSET);
 | 
			
		||||
 | 
			
		||||
@@ -237,3 +277,173 @@ void lcd_deinit()
 | 
			
		||||
	lcd_port_clear();
 | 
			
		||||
	rcc_manager_disable_clock(&RCC->AHB1ENR, BITMASK_TO_BITNO(LCD_RCC_MASK));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint8_t compare_input_to_shadow(const char (*display_buffer)[21])
 | 
			
		||||
{
 | 
			
		||||
	uint8_t ret = 0;
 | 
			
		||||
	int i, row;
 | 
			
		||||
 | 
			
		||||
	for (row = 0; row < 4; row++) {
 | 
			
		||||
		for (i = 0; i < 20; i++) {
 | 
			
		||||
			if (display_buffer[row][i] != shadow_display[row][i]) {
 | 
			
		||||
				ret |= (1U<<row);
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_fsm_enable(bool en)
 | 
			
		||||
{
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
 | 
			
		||||
	if (en)
 | 
			
		||||
		LCD_DPORT->ODR |= LCD_E_MASK;
 | 
			
		||||
	else
 | 
			
		||||
		LCD_DPORT->ODR &= ~LCD_E_MASK;
 | 
			
		||||
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
	__ASM("nop");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_fsm_write_command(bool high, uint8_t cmd)
 | 
			
		||||
{
 | 
			
		||||
	lcd_port_clear();
 | 
			
		||||
 | 
			
		||||
	if (high)
 | 
			
		||||
		lcd_out((cmd >> 4) & 0x0F);
 | 
			
		||||
	else
 | 
			
		||||
		lcd_out((cmd) & 0x0F);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void lcd_fsm_write_data(bool high, uint8_t data)
 | 
			
		||||
{
 | 
			
		||||
	LCD_DPORT->ODR |= (1<<LCD_RS);
 | 
			
		||||
	if (high)
 | 
			
		||||
		lcd_out((data >> 4) & 0x0F);
 | 
			
		||||
	else
 | 
			
		||||
		lcd_out((data) & 0x0F);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum lcd_fsm_ret lcd_fsm_write_buffer(const char (*display_buffer)[21])
 | 
			
		||||
{
 | 
			
		||||
	static bool idle = true;
 | 
			
		||||
	static uint8_t rows_to_handle = 0;
 | 
			
		||||
	static uint32_t state_cnt;
 | 
			
		||||
	static uint8_t row_cnt = 0;
 | 
			
		||||
	static uint32_t char_cnt;
 | 
			
		||||
	static uint32_t line_len;
 | 
			
		||||
	static uint64_t timestamp = 0ULL;
 | 
			
		||||
	enum lcd_fsm_ret ret;
 | 
			
		||||
 | 
			
		||||
	ret = LCD_FSM_NOP;
 | 
			
		||||
 | 
			
		||||
	if (idle) {
 | 
			
		||||
		rows_to_handle = compare_input_to_shadow(display_buffer);
 | 
			
		||||
		memcpy(shadow_display, display_buffer, sizeof(shadow_display));
 | 
			
		||||
		shadow_display[0][20] = 0;
 | 
			
		||||
		shadow_display[1][20] = 0;
 | 
			
		||||
		shadow_display[2][20] = 0;
 | 
			
		||||
		shadow_display[3][20] = 0;
 | 
			
		||||
		state_cnt = 0;
 | 
			
		||||
		row_cnt = 0;
 | 
			
		||||
		idle = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (rows_to_handle == 0) {
 | 
			
		||||
		idle = true;
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ((rows_to_handle & (1<<row_cnt))) {
 | 
			
		||||
		switch (state_cnt) {
 | 
			
		||||
		case 0:
 | 
			
		||||
			lcd_fsm_write_command(true, lcd_get_set_cursor_cmd(0, row_cnt));
 | 
			
		||||
			line_len = strlen(&shadow_display[row_cnt][0]);
 | 
			
		||||
			char_cnt = 0;
 | 
			
		||||
			lcd_fsm_enable(true);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 1:
 | 
			
		||||
			lcd_fsm_enable(false);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 2:
 | 
			
		||||
			lcd_fsm_write_command(false, lcd_get_set_cursor_cmd(0, row_cnt));
 | 
			
		||||
			lcd_fsm_enable(true);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 3:
 | 
			
		||||
			lcd_fsm_enable(false);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			timestamp = systick_get_global_tick();
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 4:
 | 
			
		||||
			if (!systick_ticks_have_passed(timestamp, 5)) {
 | 
			
		||||
				ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			} else {
 | 
			
		||||
				ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
				state_cnt++;
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		case 5:
 | 
			
		||||
			lcd_fsm_write_data(true, (char_cnt >= line_len) ? ' ' : shadow_display[row_cnt][char_cnt]);
 | 
			
		||||
			lcd_fsm_enable(true);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 6:
 | 
			
		||||
			lcd_fsm_enable(false);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 7:
 | 
			
		||||
			lcd_fsm_write_data(false, (char_cnt >= line_len) ? ' ' : shadow_display[row_cnt][char_cnt]);
 | 
			
		||||
			lcd_fsm_enable(true);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			state_cnt++;
 | 
			
		||||
			break;
 | 
			
		||||
		case 8:
 | 
			
		||||
			lcd_fsm_enable(false);
 | 
			
		||||
			ret = LCD_FSM_WAIT_CALL;
 | 
			
		||||
			char_cnt++;
 | 
			
		||||
			if (char_cnt < 20) {
 | 
			
		||||
				state_cnt = 5;
 | 
			
		||||
			} else {
 | 
			
		||||
				state_cnt = 0;
 | 
			
		||||
				rows_to_handle &= (uint8_t)~(1U<<row_cnt);
 | 
			
		||||
				if (row_cnt < 3) {
 | 
			
		||||
					row_cnt++;
 | 
			
		||||
				} else {
 | 
			
		||||
					idle = true;
 | 
			
		||||
					row_cnt = 0;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			ret = LCD_FSM_NOP;
 | 
			
		||||
			idle = true;
 | 
			
		||||
			rows_to_handle = 0U;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (row_cnt < 3) {
 | 
			
		||||
			row_cnt++;
 | 
			
		||||
			ret = LCD_FSM_CALL_AGAIN;
 | 
			
		||||
		} else {
 | 
			
		||||
			row_cnt = 0;
 | 
			
		||||
			ret = LCD_FSM_NOP;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user