Skip to content

Instantly share code, notes, and snippets.

@ak1211
Created Nov 23, 2021
Embed
What would you like to do?
/*
* i2c_lcd.c
*
* Created on: 2021/11/22
* Author: Akihiro Yamamoto
*
* Copyright 2021 Akihiro Yamamoto
* Licensed under the Apache License, Version 2.0
*
*/
#include "main.h"
#include <stdint.h>
#include <string.h>
#include <i2c_lcd.h>
#if __STDC_VERSION__ >= 199901L
#else
#error ISO C99 or newer compiler required.
#endif
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#define I2C_LCD_TIMEOUT ((uint8_t)100)
#define I2C_LCD_ADDRESS ((uint8_t)0x3e)
#define I2C_LCD_CBYTE_COMMAND ((uint8_t)0x00)
#define I2C_LCD_CBYTE_DATA ((uint8_t)0x40)
#define I2C_LCD_CBYTE_CONTINUATION ((uint8_t)0x80)
typedef struct {
icon_code_t icon_code;
uint8_t addr;
uint8_t bit;
} icon_t;
// @formatter:off
static const icon_t I2C_LCD_ICON_DATA[13] = {
{ I2C_LCD_ICON_a, 0x00, 0b10000 }, // S1 ANTENNA
{ I2C_LCD_ICON_b, 0x02, 0b10000 }, // S11 TEL
{ I2C_LCD_ICON_c, 0x04, 0b10000 }, // S21
{ I2C_LCD_ICON_d, 0x06, 0b10000 }, // S31
{ I2C_LCD_ICON_e, 0x07, 0b10000 }, // S36 UP ARROW
{ I2C_LCD_ICON_f, 0x07, 0b01000 }, // S37 DOWN ARROW
{ I2C_LCD_ICON_g, 0x09, 0b10000 }, // S46 LOCKED
{ I2C_LCD_ICON_h, 0x0b, 0b10000 }, // S56
{ I2C_LCD_ICON_i, 0x0d, 0b10000 }, // S66 BATTERY LOW
{ I2C_LCD_ICON_j, 0x0d, 0b01000 }, // S67 BATTERY MID
{ I2C_LCD_ICON_k, 0x0d, 0b00100 }, // S68 BATTERY HIGH
{ I2C_LCD_ICON_l, 0x0d, 0b00010 }, // S69 BATTERY FRAME
{ I2C_LCD_ICON_m, 0x0f, 0b10000 }, // S76
};
// @formatter:on
// @formatter:off
inline static void i2c_lcd_wait_a_moment() {
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
// 10
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
// 20
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
// 30
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
// 40
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP");
// 50
}
// @formatter:on
void i2c_lcd_init(I2C_HandleTypeDef *hi2c) {
uint8_t contrast = 0b101000;
/* first step */
{
// @formatter:off
uint8_t sequence[] = {
0b00111000, // function set
0b00111001, // function set
0b00010100, // interval osc
0b01110000 | (contrast & 0xf), // contrast Low
0b01011100 | ((contrast >> 4) & 0x3), // contast High/icon/power
0b01101100, // follower control
};
// @formatter:on
i2c_lcd_send_commands(hi2c, ARRAY_SIZE(sequence), sequence);
}
HAL_Delay(200);
/* second step */
{
// @formatter:off
uint8_t sequence[] = {
0b00111000, // function set
0b00001100, // Display On
0b00000001, // Clear Display
};
// @formatter:on
i2c_lcd_send_commands(hi2c, ARRAY_SIZE(sequence), sequence);
}
HAL_Delay(2);
}
static void master_transmit(I2C_HandleTypeDef *hi2c, uint8_t cbyte, size_t size, uint8_t data[size]) {
size_t i;
uint8_t buff[size * 2];
for (i = 0; i < (size - 1); ++i) {
buff[i * 2 + 0] = I2C_LCD_CBYTE_CONTINUATION | cbyte;
buff[i * 2 + 1] = data[i];
}
buff[i * 2 + 0] = cbyte;
buff[i * 2 + 1] = data[i];
HAL_I2C_Master_Transmit(hi2c, I2C_LCD_ADDRESS << 1, buff, ARRAY_SIZE(buff),
I2C_LCD_TIMEOUT);
i2c_lcd_wait_a_moment();
}
void i2c_lcd_send_commands(I2C_HandleTypeDef *hi2c, size_t size,
uint8_t cmds[size]) {
master_transmit(hi2c, I2C_LCD_CBYTE_COMMAND, size, cmds);
}
void i2c_lcd_send_data(I2C_HandleTypeDef *hi2c, size_t size, uint8_t data[size]) {
master_transmit(hi2c, I2C_LCD_CBYTE_DATA, size, data);
}
void i2c_lcd_puts(I2C_HandleTypeDef *hi2c, char *s) {
i2c_lcd_send_data(hi2c, strlen(s), (uint8_t*) s);
}
void i2c_lcd_show_icon(I2C_HandleTypeDef *hi2c, icon_code_t bitflag) {
uint8_t buff[16] = { 0 };
for (uint8_t i = 0; i < ARRAY_SIZE(I2C_LCD_ICON_DATA); ++i) {
const icon_t *p = &I2C_LCD_ICON_DATA[i];
if (bitflag & p->icon_code) {
buff[p->addr] |= p->bit;
}
}
for (uint8_t addr = 0; addr < ARRAY_SIZE(buff); ++addr) {
// @formatter:off
uint8_t cmds[] = {
0b00111001, // function set
0b01000000 | addr, // set icon address
};
// @formatter:on
i2c_lcd_send_commands(hi2c, ARRAY_SIZE(cmds), cmds);
i2c_lcd_send_datum(hi2c, buff[addr]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment