/* Multitasking Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include <esp_log.h>
#include "sdkconfig.h"
#include "rom/ets_sys.h"
#include <esp_log.h>
#include "HD44780.h"
// LCD module defines
#define LCD_LINEONE 0x00 // start of line 1
#define LCD_LINETWO 0x40 // start of line 2
#define LCD_LINETHREE 0x14 // start of line 3
#define LCD_LINEFOUR 0x54 // start of line 4
#define LCD_BACKLIGHT 0x08
#define LCD_ENABLE 0x04
#define LCD_COMMAND 0x00
#define LCD_WRITE 0x01
#define LCD_SET_DDRAM_ADDR 0x80
#define LCD_READ_BF 0x40
// LCD instructions
#define LCD_CLEAR 0x01 // replace all characters with ASCII 'space'
#define LCD_HOME 0x02 // return cursor to first position on first line
#define LCD_ENTRY_MODE 0x06 // shift cursor from left to right on read/write
#define LCD_DISPLAY_OFF 0x08 // turn display off
#define LCD_DISPLAY_ON 0x0C // display on, cursor off, don't blink character
#define LCD_FUNCTION_RESET 0x30 // reset the LCD
#define LCD_FUNCTION_SET_4BIT 0x28 // 4-bit data, 2-line display, 5 x 7 font
#define LCD_SET_CURSOR 0x80 // set cursor position
// Pin mappings
// P0 -> RS
// P1 -> RW
// P2 -> E
// P3 -> Backlight
// P4 -> D4
// P5 -> D5
// P6 -> D6
// P7 -> D7
static char tag[] = "LCD Driver";
static uint8_t LCD_addr;
static uint8_t SDA_pin;
static uint8_t SCL_pin;
static uint8_t LCD_cols;
static uint8_t LCD_rows;
static void LCD_writeNibble(uint8_t nibble, uint8_t mode);
static void LCD_writeByte(uint8_t data, uint8_t mode);
static void LCD_pulseEnable(uint8_t nibble);
static esp_err_t I2C_init(void)
{
i2c_config_t conf;
/*
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = SDA_pin,
.scl_io_num = SCL_pin,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000
};
*/
conf.mode = I2C_MODE_MASTER;
conf.sda_io_num = SDA_pin;
conf.scl_io_num = SCL_pin;
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
conf.master.clk_speed = 10000;
conf.clk_flags = I2C_SCLK_SRC_FLAG_FOR_NOMAL;
i2c_param_config(I2C_NUM_0, &conf);
i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
return ESP_OK;
}
void LCD_init(uint8_t addr, uint8_t dataPin, uint8_t clockPin, uint8_t cols, uint8_t rows)
{
LCD_addr = addr;
SDA_pin = dataPin;
SCL_pin = clockPin;
LCD_cols = cols;
LCD_rows = rows;
I2C_init();
vTaskDelay(100 / portTICK_RATE_MS); // Initial 40 mSec delay
// Reset the LCD controller
LCD_writeNibble(LCD_FUNCTION_RESET, LCD_COMMAND); // First part of reset sequence
vTaskDelay(10 / portTICK_RATE_MS); // 4.1 mS delay (min)
LCD_writeNibble(LCD_FUNCTION_RESET, LCD_COMMAND); // second part of reset sequence
ets_delay_us(200); // 100 uS delay (min)
LCD_writeNibble(LCD_FUNCTION_RESET, LCD_COMMAND); // Third time's a charm
LCD_writeNibble(LCD_FUNCTION_SET_4BIT, LCD_COMMAND); // Activate 4-bit mode
ets_delay_us(80); // 40 uS delay (min)
// --- Busy flag now available ---
// Function Set instruction
LCD_writeByte(LCD_FUNCTION_SET_4BIT, LCD_COMMAND); // Set mode, lines, and font
ets_delay_us(80);
// Clear Display instruction
LCD_writeByte(LCD_CLEAR, LCD_COMMAND); // clear display RAM
vTaskDelay(2 / portTICK_RATE_MS); // Clearing memory takes a bit longer
// Entry Mode Set instruction
LCD_writeByte(LCD_ENTRY_MODE, LCD_COMMAND); // Set desired shift characteristics
ets_delay_us(80);
LCD_writeByte(LCD_DISPLAY_ON, LCD_COMMAND); // Ensure LCD is set to on
}
void LCD_setCursor(uint8_t col, uint8_t row)
{
if (row > LCD_rows - 1) {
ESP_LOGE(tag, "Cannot write to row %d. Please select a row in the range (0, %d)", row, LCD_rows-1);
row = LCD_rows - 1;
}
uint8_t row_offsets[] = {LCD_LINEONE, LCD_LINETWO, LCD_LINETHREE, LCD_LINEFOUR};
LCD_writeByte(LCD_SET_DDRAM_ADDR | (col + row_offsets[row]), LCD_COMMAND);
}
void LCD_writeChar(char c)
{
LCD_writeByte(c, LCD_WRITE); // Write data to DDRAM
}
void LCD_writeStr(char* str)
{
while (*str) {
LCD_writeChar(*str++);
}
}
void LCD_home(void)
{
LCD_writeByte(LCD_HOME, LCD_COMMAND);
vTaskDelay(2 / portTICK_RATE_MS); // This command takes a while to complete
}
void LCD_clearScreen(void)
{
LCD_writeByte(LCD_CLEAR, LCD_COMMAND);
vTaskDelay(2 / portTICK_RATE_MS); // This command takes a while to complete
}
static void LCD_writeNibble(uint8_t nibble, uint8_t mode)
{
uint8_t data = (nibble & 0xF0) | mode | LCD_BACKLIGHT;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (LCD_addr << 1) | I2C_MASTER_WRITE, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data, 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS));
i2c_cmd_link_delete(cmd);
LCD_pulseEnable(data); // Clock data into LCD
}
static void LCD_writeByte(uint8_t data, uint8_t mode)
{
LCD_writeNibble(data & 0xF0, mode);
LCD_writeNibble((data << 4) & 0xF0, mode);
}
static void LCD_pulseEnable(uint8_t data)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (LCD_addr << 1) | I2C_MASTER_WRITE, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, data | LCD_ENABLE, 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS));
i2c_cmd_link_delete(cmd);
ets_delay_us(1);
cmd = i2c_cmd_link_create();
ESP_ERROR_CHECK(i2c_master_start(cmd));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (LCD_addr << 1) | I2C_MASTER_WRITE, 1));
ESP_ERROR_CHECK(i2c_master_write_byte(cmd, (data & ~LCD_ENABLE), 1));
ESP_ERROR_CHECK(i2c_master_stop(cmd));
ESP_ERROR_CHECK(i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000/portTICK_PERIOD_MS));
i2c_cmd_link_delete(cmd);
ets_delay_us(500);
}
/*
void LCD_init(uint8_t addr, uint8_t dataPin, uint8_t clockPin, uint8_t cols, uint8_t rows);
void LCD_setCursor(uint8_t col, uint8_t row);
void LCD_home(void);
void LCD_clearScreen(void);
void LCD_writeChar(char c);
void LCD_writeStr(char* str);
*/
#define LED_RED GPIO_NUM_5
#define LED_GREEN GPIO_NUM_2
#define LED_BLUE GPIO_NUM_4
#define LCD_ADDR 0x27
#define SDA_PIN 21
#define SCL_PIN 22
#define LCD_COLS 16
#define LCD_ROWS 2
struct led_task_parameters_t
{
gpio_num_t led_gpio;
TickType_t blink_time;
};
static led_task_parameters_t red_led_gpio = {LED_RED, 2000};
static led_task_parameters_t blue_led_gpio = {LED_BLUE, 1000};
static led_task_parameters_t green_led_gpio = {LED_GREEN, 500};
void led_task(void *pvParameter)
{
gpio_num_t led_gpio = ((led_task_parameters_t *)pvParameter)->led_gpio;
TickType_t blink_time = ((led_task_parameters_t *)pvParameter)->blink_time;
uint8_t led_value = 0;
gpio_reset_pin(led_gpio);
gpio_set_direction(led_gpio, GPIO_MODE_OUTPUT);
while (1) {
gpio_set_level(led_gpio, led_value);
led_value = !led_value;
vTaskDelay(blink_time / portTICK_PERIOD_MS);
}
vTaskDelete( NULL );
}
void hello_task(void *pvParameter)
{
while (1) {
printf("Hello world!\n");
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_RATE_MS);
}
printf("Restarting now.\n");
fflush(stdout);
//esp_restart();
}
}
void LCD_DemoTask(void* param)
{
char num[20];
while (true) {
LCD_home();
LCD_clearScreen();
LCD_writeStr("16x2 I2C LCD");
vTaskDelay(3000 / portTICK_RATE_MS);
LCD_clearScreen();
LCD_writeStr("Lets Count 0-10!");
vTaskDelay(3000 / portTICK_RATE_MS);
LCD_clearScreen();
for (int i = 0; i <= 10; i++) {
LCD_setCursor(8, 2);
sprintf(num, "%d", i);
LCD_writeStr(num);
vTaskDelay(1000 / portTICK_RATE_MS);
}
}
}
extern "C" void app_main()
{
LCD_init(LCD_ADDR, SDA_PIN, SCL_PIN, LCD_COLS, LCD_ROWS);
xTaskCreate(&LCD_DemoTask, "Demo Task", 2048, NULL, 5, NULL);
xTaskCreate(
&led_task, // task function
"red_led_task", // task name
2048, // stack size in words
&red_led_gpio, // pointer to parameters
5, // priority
NULL); // out pointer to task handle
#if 1
xTaskCreate(
&led_task, // task function
"blue_led_task", // task name
2048, // stack size in words
&blue_led_gpio, // pointer to parameters
5, // priority
NULL); // out pointer to task handle
#endif
#if 1
xTaskCreate(
&led_task, // task function
"green_led_task", // task name
2048, // stack size in words
&green_led_gpio, // pointer to parameters
5, // priority
NULL); // out pointer to task handle
#endif
xTaskCreate(&hello_task, "hello_task", 2048, NULL, 5, NULL);
}
esp:VIN
esp:GND.2
esp:D13
esp:D12
esp:D14
esp:D27
esp:D26
esp:D25
esp:D33
esp:D32
esp:D35
esp:D34
esp:VN
esp:VP
esp:EN
esp:3V3
esp:GND.1
esp:D15
esp:D2
esp:D4
esp:RX2
esp:TX2
esp:D5
esp:D18
esp:D19
esp:D21
esp:RX0
esp:TX0
esp:D22
esp:D23
led-red:A
led-red:C
led-green:A
led-green:C
led-blue:A
led-blue:C
lcd1:GND
lcd1:VCC
lcd1:SDA
lcd1:SCL