Initial commit, LCD, RE, Moisture, Keypad working, TODO I2C

master
Ondřej Hruška 11 months ago
commit 89c1857d57
  1. 3
      .gitignore
  2. 23
      CMakeLists.txt
  3. 14
      Makefile
  4. 73
      pico_sdk_import.cmake
  5. 396
      src/lcd.c
  6. 294
      src/lcd.c.bak
  7. 62
      src/lcd.h
  8. 161
      src/main.c
  9. 29
      src/pinout.h

3
.gitignore vendored

@ -0,0 +1,3 @@
build/
cmake-build-*
.idea/

@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.13)
# initialize the SDK based on PICO_SDK_PATH
# note: this must happen before project()
include(pico_sdk_import.cmake)
project(zavlaha)
# initialize the Raspberry Pi Pico SDK
pico_sdk_init()
# rest of your project
add_executable(zavlaha
src/main.c
src/lcd.c
)
# Add pico_stdlib library which aggregates commonly used features
target_link_libraries(zavlaha pico_stdlib hardware_i2c hardware_adc hardware_irq)
# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(zavlaha)

@ -0,0 +1,14 @@
.PHONY: build
TARGET=build/zavlaha.elf
TARGET_U2F=build/zavlaha.uf2
build:
cd build && cmake .. && make -j
arm-none-eabi-size ${TARGET}
upload: build $(TARGET_U2F)
cp $(TARGET_U2F) /run/media/ondra/RPI-RP2/
flash: build
pico-openocd -f target/rp2040.cfg -c "adapter speed 1000" -c "program ${TARGET} verify reset exit"

@ -0,0 +1,73 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
endif ()
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})

@ -0,0 +1,396 @@
#include <stdbool.h>
#include <stdint.h>
#include <pico/stdlib.h>
#include "lcd.h"
#include "pinout.h"
#define LCD_D7 PIN_LCD_D7
#define LCD_D6 PIN_LCD_D6
#define LCD_D5 PIN_LCD_D5
#define LCD_D4 PIN_LCD_D4
#define LCD_RS PIN_LCD_RS
#define LCD_RW PIN_LCD_RW
#define LCD_E PIN_LCD_E
#define set_pin(num, val) gpio_put((num), (val))
#define get_pin(num) gpio_get((num))
#define pin_high(num) set_pin((num), 1)
#define pin_low(num) set_pin((num), 0)
#define get_bit(a, pos) (((a) >> (pos)) & 1)
#define as_output(pin) gpio_set_dir((pin), 1)
#define as_input_pu(pin) do { gpio_set_dir((pin), 0); gpio_pull_up((pin)); } while (0)
#define _delay_ms(ms) sleep_ms((ms))
#define _delay_us(us) sleep_us((us))
#define _delay_ns(ns) sleep_us(1 + ((ns) / 1000)) // TODO
// Start address of rows
const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
// Internal prototypes
void _lcd_mode_r();
void _lcd_mode_w();
void _lcd_clk();
void _lcd_wait_bf();
void _lcd_write_byte(uint8_t bb);
uint8_t _lcd_read_byte();
void lcd_command(uint8_t bb);
// Write utilities
#define _lcd_write_low(bb) _lcd_write_nibble((bb) & 0x0F)
#define _lcd_write_high(bb) _lcd_write_nibble(((bb) & 0xF0) >> 4)
#define _lcd_write_nibble(nib) \
gpio_put_masked((1 << PIN_LCD_D7) | (1 << PIN_LCD_D6) | (1 << PIN_LCD_D5) | (1 << PIN_LCD_D4), (nib) << PIN_LCD_D4)
//#define _lcd_write_nibble(nib) do { \
// set_pin(LCD_D7, get_bit((nib), 3)); \
// set_pin(LCD_D6, get_bit((nib), 2)); \
// set_pin(LCD_D5, get_bit((nib), 1)); \
// set_pin(LCD_D4, get_bit((nib), 0)); \
//} while(0)
// --- Commands ---
// Clear screen (reset)
#define LCD_CLEAR 0b00000001
// Move cursor to (0,0), unshift...
#define LCD_HOME 0b00000010
// Set mode: Increment + NoShift
#define LCD_MODE_INC 0b00000110
// Set mode: Increment + Shift
#define LCD_MODE_INC_SHIFT 0b00000111
// Set mode: Decrement + NoShift
#define LCD_MODE_DEC 0b00000100
// Set mode: Decrement + Shift
#define LCD_MODE_DEC_SHIFT 0b00000101
// Disable display (data remains untouched)
#define LCD_DISABLE 0b00001000
// Disable cursor
#define LCD_CURSOR_NONE 0b00001100
// Set cursor to still underscore
#define LCD_CURSOR_BAR 0b00001110
// Set cursor to blinking block
#define LCD_CURSOR_BLINK 0b00001101
// Set cursor to both of the above at once
#define LCD_CURSOR_BOTH (LCD_CURSOR_BAR | LCD_CURSOR_BLINK)
// Move cursor
#define LCD_MOVE_LEFT 0b00010000
#define LCD_MOVE_RIGHT 0b00010100
// Shift display
#define LCD_SHIFT_LEFT 0b00011000
#define LCD_SHIFT_RIGHT 0b00011100
// Set iface to 5x7 font, 1-line
#define LCD_IFACE_4BIT_1LINE 0b00100000
#define LCD_IFACE_8BIT_1LINE 0b00110000
// Set iface to 5x7 font, 2-line
#define LCD_IFACE_4BIT_2LINE 0b00101000
#define LCD_IFACE_8BIT_2LINE 0b00111000
// 0 W, 1 R
bool _lcd_mode;
struct {
uint8_t x;
uint8_t y;
} _pos;
enum {
TEXT = 0,
CG = 1
} _addrtype;
/** Initialize the display */
void lcd_init()
{
// configure pins as output
as_output(LCD_E);
as_output(LCD_RW);
as_output(LCD_RS);
_lcd_mode = 1; // force data pins to output
_lcd_mode_w();
// Magic sequence to invoke Cthulhu (or enter 4-bit mode)
_delay_ms(16);
_lcd_write_nibble(0b0011);
_lcd_clk();
_delay_ms(5);
_lcd_clk();
_delay_ms(5);
_lcd_clk();
_delay_ms(5);
_lcd_write_nibble(0b0010);
_lcd_clk();
_delay_us(100);
// Configure the display
lcd_command(LCD_IFACE_4BIT_2LINE);
lcd_command(LCD_DISABLE);
lcd_command(LCD_CLEAR);
lcd_command(LCD_MODE_INC);
// mark as enabled
lcd_enable();
_pos.x = 0;
_pos.y = 0;
_addrtype = TEXT;
}
/** Send a pulse on the ENABLE line */
void _lcd_clk()
{
pin_high(LCD_E);
_delay_ns(450);
pin_low(LCD_E);
_delay_ns(450);
}
/** Enter READ mode */
void _lcd_mode_r()
{
if (_lcd_mode == 1) { return; } // already in R mode
pin_high(LCD_RW);
as_input_pu(LCD_D7);
as_input_pu(LCD_D6);
as_input_pu(LCD_D5);
as_input_pu(LCD_D4);
_lcd_mode = 1;
}
/** Enter WRITE mode */
void _lcd_mode_w()
{
if (_lcd_mode == 0) { return; } // already in W mode
pin_low(LCD_RW);
as_output(LCD_D7);
as_output(LCD_D6);
as_output(LCD_D5);
as_output(LCD_D4);
_lcd_mode = 0;
}
/** Read a byte */
uint8_t _lcd_read_byte()
{
_lcd_mode_r();
uint8_t res = 0;
_lcd_clk();
res = (get_pin(LCD_D7) << 7) | (get_pin(LCD_D6) << 6) | (get_pin(LCD_D5) << 5) | (get_pin(LCD_D4) << 4);
_lcd_clk();
res |= (get_pin(LCD_D7) << 3) | (get_pin(LCD_D6) << 2) | (get_pin(LCD_D5) << 1) | (get_pin(LCD_D4) << 0);
return res;
}
/** Write an instruction byte */
void lcd_command(uint8_t bb)
{
_lcd_wait_bf();
pin_low(LCD_RS); // select instruction register
_lcd_write_byte(bb); // send instruction byte
}
/** Write a data byte */
void lcd_write(uint8_t bb)
{
if (_addrtype == TEXT) {
if (bb == '\r') {
// CR
_pos.x = 0;
lcd_xy(_pos.x, _pos.y);
return;
}
if (bb == '\n') {
// LF
_pos.y++;
lcd_xy(_pos.x, _pos.y);
return;
}
_pos.x++;
}
_lcd_wait_bf();
pin_high(LCD_RS); // select data register
_lcd_write_byte(bb); // send data byte
}
/** Read BF & Address */
uint8_t lcd_read_bf_addr()
{
pin_low(LCD_RS);
return _lcd_read_byte();
}
/** Read CGRAM or DDRAM */
uint8_t lcd_read()
{
if (_addrtype == TEXT) { _pos.x++; }
pin_high(LCD_RS);
return _lcd_read_byte();
}
/** Write a byte using the 4-bit interface */
void _lcd_write_byte(uint8_t bb)
{
_lcd_mode_w(); // enter W mode
_lcd_write_high(bb);
_lcd_clk();
_lcd_write_low(bb);
_lcd_clk();
}
/** Wait until the device is ready */
void _lcd_wait_bf()
{
uint8_t d = 0;
while (d++ < 200 && lcd_read_bf_addr() & (1 << 7))
_delay_us(1);
}
/** Send a string to LCD */
void lcd_puts(char *str_p)
{
char c;
while ((c = *str_p++)) {
lcd_putc(c);
}
}
/** Sedn a char to LCD */
void lcd_putc(const char c)
{
lcd_write(c);
}
/** Set cursor position */
void lcd_xy(const uint8_t x, const uint8_t y)
{
_pos.x = x;
_pos.y = y;
lcd_addr(LCD_ROW_ADDR[y] + (x));
}
uint8_t _lcd_old_cursor = CURSOR_NONE;
bool _lcd_enabled = false;
/** Set LCD cursor. If not enabled, only remember it. */
void lcd_cursor(uint8_t type)
{
_lcd_old_cursor = (type & CURSOR_BOTH);
if (_lcd_enabled) { lcd_command(LCD_CURSOR_NONE | _lcd_old_cursor); }
}
/** Display display (preserving cursor) */
void lcd_disable()
{
lcd_command(LCD_DISABLE);
_lcd_enabled = false;
}
/** Enable display (restoring cursor) */
void lcd_enable()
{
_lcd_enabled = true;
lcd_cursor(_lcd_old_cursor);
}
/** Go home */
void lcd_home()
{
lcd_command(LCD_HOME);
_pos.x = 0;
_pos.y = 0;
_addrtype = TEXT;
}
/** Clear the screen */
void lcd_clear()
{
lcd_command(LCD_CLEAR);
_pos.x = 0;
_pos.y = 0;
_addrtype = TEXT;
_delay_ms(1); // it tends to lose the first character otherwise!
}
/** Define a glyph */
void lcd_glyph(const uint8_t index, const uint8_t *array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
lcd_write(array[i]);
}
// restore previous position
lcd_xy(_pos.x, _pos.y);
_addrtype = TEXT;
}
/** Set address in CGRAM */
void lcd_addr_cg(const uint8_t acg)
{
_addrtype = CG;
lcd_command(0b01000000 | ((acg) & 0b00111111));
}
/** Set address in DDRAM */
void lcd_addr(const uint8_t add)
{
_addrtype = TEXT;
lcd_command(0b10000000 | ((add) & 0b01111111));
}

@ -0,0 +1,294 @@
#include <stdbool.h>
#include <stdint.h>
#include <pico/stdlib.h>
#include "pinout.h"
#include "lcd.h"
// ------------------ PORTING ----------------------
#define lcd_mode_instr(bb) gpio_put(PIN_LCD_DC, 0)
#define lcd_mode_data(bb) gpio_put(PIN_LCD_DC, 1)
#define lcd_mode_write(bb) gpio_put(PIN_LCD_RW, 0)
#define lcd_mode_read(bb) gpio_put(PIN_LCD_RW, 1)
//// Write utilities
//#define lcd_write_nibble(nib) \
// gpio_put_masked((1 << PIN_LCD_D7) | (1 << PIN_LCD_D6) | (1 << PIN_LCD_D5) | (1 << PIN_LCD_D4), (nib) << PIN_LCD_D4)
// Write utilities
#define lcd_write_nibble(nib) do { \
gpio_put(PIN_LCD_D7, nib & 0b1000); \
gpio_put(PIN_LCD_D6, nib & 0b0100); \
gpio_put(PIN_LCD_D5, nib & 0b0010); \
gpio_put(PIN_LCD_D4, nib & 0b0001); \
} while (0)
/** Wait until the device is ready */
static void lcd_wait_ready()
{
sleep_us(160);
}
/** Send a pulse on the ENABLE line */
static inline void lcd_clk()
{
gpio_put(PIN_LCD_CLK, 1);
sleep_us(1);
gpio_put(PIN_LCD_CLK, 0);
sleep_us(1);
}
// ---------------------------------------------------------------
// --- Commands ---
// Clear screen (reset)
#define LCD_CLEAR 0b00000001
// Move cursor to (0,0), unshift...
#define LCD_HOME 0b00000010
// Set mode: Increment + NoShift
#define LCD_MODE_INC 0b00000110
// Set mode: Increment + Shift
#define LCD_MODE_INC_SHIFT 0b00000111
// Set mode: Decrement + NoShift
#define LCD_MODE_DEC 0b00000100
// Set mode: Decrement + Shift
#define LCD_MODE_DEC_SHIFT 0b00000101
// Disable display (data remains untouched)
#define LCD_DISABLE 0b00001000
// Disable cursor
#define LCD_CURSOR_NONE 0b00001100
// Set cursor to still underscore
#define LCD_CURSOR_BAR 0b00001110
// Set cursor to blinking block
#define LCD_CURSOR_BLINK 0b00001101
// Set cursor to both of the above at once
#define LCD_CURSOR_BOTH (LCD_CURSOR_BAR | LCD_CURSOR_BLINK)
// Move cursor
#define LCD_MOVE_LEFT 0b00010000
#define LCD_MOVE_RIGHT 0b00010100
// Shift display
#define LCD_SHIFT_LEFT 0b00011000
#define LCD_SHIFT_RIGHT 0b00011100
// Set iface to 5x7 font, 1-line
#define LCD_IFACE_4BIT_1LINE 0b00100000
#define LCD_IFACE_8BIT_1LINE 0b00110000
// Set iface to 5x7 font, 2-line
#define LCD_IFACE_4BIT_2LINE 0b00101000
#define LCD_IFACE_8BIT_2LINE 0b00111000
/** Write an instruction byte */
static void lcd_command(uint8_t bb);
/** Write a data byte, waiting for ready and handling CRLF if in text mode */
static void lcd_write(uint8_t bb);
/** Write a byte (handles just the data pins and clk) */
static void lcd_write_byte(uint8_t bb);
#define lcd_write_low(bb) lcd_write_nibble((bb) & 0x0F)
#define lcd_write_high(bb) lcd_write_nibble(((bb) & 0xF0) >> 4)
static struct {
uint8_t x;
uint8_t y;
} lcd_pos;
static enum {
LCD_ADDRTYPE_TEXT = 0,
LCD_ADDRTYPE_CG = 1
} lcd_addrtype;
static uint8_t lcd_old_cursor = CURSOR_NONE;
static bool lcd_enabled = false;
// Start address of rows
const uint8_t LCD_ROW_ADDR[] = {0x00, 0x40, 0x14, 0x54};
/** Initialize the display */
void lcd_init()
{
// Magic sequence to invoke Cthulhu (or enter 4-bit mode)
sleep_ms(100);
lcd_write_nibble(0b0011);
lcd_clk();
sleep_ms(5);
lcd_clk();
sleep_ms(1);
lcd_clk();
sleep_ms(1);
lcd_write_nibble(0b0010);
lcd_clk();
sleep_us(100);
// Configure the display
lcd_command(LCD_IFACE_4BIT_2LINE);
lcd_command(LCD_DISABLE);
lcd_command(LCD_CLEAR);
lcd_command(LCD_MODE_INC);
// mark as enabled
lcd_enable();
lcd_pos.x = 0;
lcd_pos.y = 0;
lcd_addrtype = LCD_ADDRTYPE_TEXT;
}
/** Write an instruction byte */
void lcd_command(uint8_t bb)
{
lcd_wait_ready();
lcd_mode_instr();
lcd_write_byte(bb); // send instruction byte
}
/** Write a data byte */
void lcd_write(uint8_t bb)
{
if (lcd_addrtype == LCD_ADDRTYPE_TEXT) {
if (bb == '\r') {
// CR
lcd_pos.x = 0;
lcd_xy(lcd_pos.x, lcd_pos.y);
return;
}
if (bb == '\n') {
// LF
lcd_pos.y++;
lcd_xy(lcd_pos.x, lcd_pos.y);
return;
}
lcd_pos.x++;
}
lcd_wait_ready();
lcd_mode_data();
lcd_write_byte(bb); // send data byte
}
/** Write a byte using the 4-bit interface */
static void lcd_write_byte(uint8_t bb)
{
lcd_write_high(bb);
lcd_clk();
lcd_write_low(bb);
lcd_clk();
}
/** Send a string to LCD */
void lcd_puts(char *str)
{
char c;
while ((c = *str++)) {
lcd_putc(c);
}
}
/** Sedn a char to LCD */
void lcd_putc(const char c)
{
lcd_write(c);
}
/** Set cursor position */
void lcd_xy(const uint8_t x, const uint8_t y)
{
lcd_pos.x = x;
lcd_pos.y = y;
lcd_addr(LCD_ROW_ADDR[y] + (x));
}
/** Set LCD cursor. If not enabled, only remember it. */
void lcd_set_cursor(uint8_t type)
{
lcd_old_cursor = (type & CURSOR_BAR_BLINK);
if (lcd_enabled) { lcd_command(LCD_CURSOR_NONE | lcd_old_cursor); }
}
/** Disable display (preserving cursor) */
void lcd_disable()
{
lcd_command(LCD_DISABLE);
lcd_enabled = false;
}
/** Enable display (restoring cursor) */
void lcd_enable()
{
lcd_enabled = true;
lcd_set_cursor(lcd_old_cursor);
}
/** Go home */
void lcd_home()
{
lcd_command(LCD_HOME);
lcd_pos.x = 0;
lcd_pos.y = 0;
lcd_addrtype = LCD_ADDRTYPE_TEXT;
}
/** Clear the screen */
void lcd_clear()
{
lcd_command(LCD_CLEAR);
lcd_pos.x = 0;
lcd_pos.y = 0;
lcd_addrtype = LCD_ADDRTYPE_TEXT;
}
/** Define a glyph */
void lcd_glyph(const uint8_t index, const uint8_t *array)
{
lcd_addr_cg(index * 8);
for (uint8_t i = 0; i < 8; ++i) {
lcd_write(array[i]);
}
// restore previous position
lcd_xy(lcd_pos.x, lcd_pos.y);
lcd_addrtype = LCD_ADDRTYPE_TEXT;
}
/** Set address in CGRAM */
void lcd_addr_cg(const uint8_t acg)
{
lcd_addrtype = LCD_ADDRTYPE_CG;
lcd_command(0b01000000 | ((acg) & 0b00111111));
}
/** Set address in DDRAM */
void lcd_addr(const uint8_t add)
{
lcd_addrtype = LCD_ADDRTYPE_TEXT;
lcd_command(0b10000000 | ((add) & 0b01111111));
}

@ -0,0 +1,62 @@
#pragma once
// HD44780 LCD display driver - 4-bit mode
//
// LCD pins are configured using a file lcd_config.h, which you
// have to add next to your main.c file.
//
// Content can be something like this:
//
//
#include <stdint.h>
#include <stdbool.h>
/** Initialize the display */
void lcd_init();
/** Send a string to LCD */
void lcd_puts(char* str_p);
/** Sedn a char to LCD */
void lcd_putc(char c);
/** Show string at X, Y */
#define lcd_puts_xy(x, y, str_p) do { lcd_xy((x), (y)); lcd_puts((str_p)); } while(0)
/** Show char at X, Y */
#define lcd_putc_xy(x, y, c) do { lcd_xy((x), (y)); lcd_putc((c)); } while(0)
/** Set cursor position */
void lcd_xy(uint8_t x, uint8_t y);
/** Set LCD cursor. If not enabled, only remember it. */
#define CURSOR_NONE 0b00
#define CURSOR_BAR 0b10
#define CURSOR_BLINK 0b01
#define CURSOR_BOTH 0b11
void lcd_set_cursor(uint8_t type);
/** Display display (preserving cursor) */
void lcd_disable();
/** Enable display (restoring cursor) */
void lcd_enable();
/** Go home */
void lcd_home();
/** Clear the screen */
void lcd_clear();
/**
* Define a glyph - 8 bytes, right 5 bits are used.
* There are total 8 custom glyphs that can be defined.
*/
void lcd_glyph(uint8_t index, const uint8_t* array);
/** Set address in CGRAM */
void lcd_addr_cg(uint8_t acg);
/** Set address in DDRAM */
void lcd_addr(uint8_t add);

@ -0,0 +1,161 @@
#include <stdio.h>
#include <pico/binary_info/code.h>
#include <pico/stdlib.h>
#include <hardware/i2c.h>
#include <hardware/adc.h>
#include <hardware/irq.h>
#include "pinout.h"
#include "lcd.h"
/*
PINOUT
Keypad - UART RX - receives symbols from STM8
LCD - HD44780
14 - RS (H-data, L-command)
15 - EN (CLK)
21,20,19,18 - D7,D6,D5,D4
RW tied low (always write)
TODO backlight switching
I2C
16 - SDA0
17 - SCL0
EEPROM 24C32 - addr 1010_000
RTC DS3231 - addr 1101_000
Relay
5, 4, 22, 26 - active high
Moisture
28 - ADC2 0-3V
*/
void setup_output(uint num)
{
gpio_set_dir(num, GPIO_OUT);
gpio_put(num, 0);
gpio_set_function(num, GPIO_FUNC_SIO);
}
// RX interrupt handler
void irq_uart() {
while (uart_is_readable(uart0)) {
uint8_t ch = uart_getc(uart0);
// TODO do something useful
if (uart_is_writable(uart0)) {
uart_putc(uart0, ch);
}
}
}
void set_relays(bool one, bool two, bool three, bool four) {
gpio_put(PIN_RE1, one);
gpio_put(PIN_RE2, two);
gpio_put(PIN_RE3, three);
gpio_put(PIN_RE1, four);
}
void open_valve(uint num) {
gpio_put(PIN_RE1, num == 1);
gpio_put(PIN_RE2, num == 2);
gpio_put(PIN_RE3, num == 3);
gpio_put(PIN_RE4, num == 4);
}
uint16_t moisture_read() {
adc_select_input(ADC_NUM_MOISTURE);
return adc_read();
}
int main()
{
// picotool binary info
bi_decl(bi_1pin_with_name(PIN_LED, "LED"));
bi_decl(bi_1pin_with_name(PIN_RE1, "RE1"));
bi_decl(bi_1pin_with_name(PIN_RE2, "RE2"));
bi_decl(bi_1pin_with_name(PIN_RE3, "RE3"));
bi_decl(bi_1pin_with_name(PIN_RE4, "RE4"));
bi_decl(bi_1pin_with_name(PIN_LCD_RS, "LCD RS"));
bi_decl(bi_1pin_with_name(PIN_LCD_E, "LCD CLK"));
bi_decl(bi_1pin_with_name(PIN_LCD_D7, "LCD D7"));
bi_decl(bi_1pin_with_name(PIN_LCD_D6, "LCD D6"));
bi_decl(bi_1pin_with_name(PIN_LCD_D5, "LCD D5"));
bi_decl(bi_1pin_with_name(PIN_LCD_D4, "LCD D4"));
bi_decl(bi_2pins_with_func(PIN_I2C_SDA, PIN_I2C_SCL, GPIO_FUNC_I2C));
bi_decl(bi_1pin_with_name(PIN_MOISTURE, "ADC (moisture)"));
bi_decl(bi_program_description("Zavlaha Kuchynka"));
setup_default_uart();
irq_set_exclusive_handler(UART0_IRQ, irq_uart);
irq_set_enabled(UART0_IRQ, true);
uart_set_irq_enables(uart0, 1, 0);
/* On-board LED */
setup_output(PIN_LED);
/* Valve relays */
setup_output(PIN_RE1);
setup_output(PIN_RE2);
setup_output(PIN_RE3);
setup_output(PIN_RE4);
/* LCD */
setup_output(PIN_LCD_RS);
setup_output(PIN_LCD_RW);
setup_output(PIN_LCD_E);
setup_output(PIN_LCD_D7);
setup_output(PIN_LCD_D6);
setup_output(PIN_LCD_D5);
setup_output(PIN_LCD_D4);
/* I2C */
i2c_init(i2c0, 100 * 1000); // 100 kbps - play it safe
gpio_set_function(PIN_I2C_SDA, GPIO_FUNC_I2C);
gpio_set_function(PIN_I2C_SCL, GPIO_FUNC_I2C);
gpio_pull_up(PIN_I2C_SDA);
gpio_pull_up(PIN_I2C_SCL);
/* ADC for moisture */
adc_init();
adc_gpio_init(PIN_MOISTURE);
lcd_init();
lcd_puts("HELLO WORLD!");
uint cnt = 0;
char buf[16];
while (1) {
lcd_clear();
lcd_puts("HELLO WORLD!");
gpio_put(PIN_LED, 1); // LED on
uint16_t moisture = moisture_read();
sprintf(buf, "ADC = %lu", moisture);
lcd_xy(0, 1);
lcd_puts(buf);
lcd_xy(15, 3);
lcd_putc('0' + cnt);
sleep_ms(100);
gpio_put(PIN_LED, 0); // LED off
sleep_ms(100);
// demo that valve control works
cnt += 1;
if (cnt == 5) {
cnt = 0;
}
open_valve(cnt);
}
}

@ -0,0 +1,29 @@
/**
* TODO file description
*/
#ifndef ZAVLAHA_PINOUT_H
#define ZAVLAHA_PINOUT_H
#define PIN_LED PICO_DEFAULT_LED_PIN // 25
#define PIN_RE1 5
#define PIN_RE2 4
#define PIN_RE3 22
#define PIN_RE4 26
#define PIN_MOISTURE 28
#define ADC_NUM_MOISTURE 2 // ADC2
#define PIN_I2C_SDA 16
#define PIN_I2C_SCL 17
#define PIN_LCD_RS 14
#define PIN_LCD_RW 6
#define PIN_LCD_E 15
#define PIN_LCD_D7 21
#define PIN_LCD_D6 20
#define PIN_LCD_D5 19
#define PIN_LCD_D4 18
// must be shifted left before adding the RW bit!
#define I2C_ADDR_EEPROM 0b1010000
#define I2C_ADDR_RTC 0b1101000
#endif //ZAVLAHA_PINOUT_H
Loading…
Cancel
Save