Created
September 8, 2022 17:17
-
-
Save threez/7d50e492cf04e9b4253cbc445609f42d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <dev/iicbus/iic.h> | |
#include <sys/ioctl.h> | |
#include <fcntl.h> | |
#include <err.h> | |
#include <string.h> | |
// commands | |
#define LCD_CLEARDISPLAY 0x01 | |
#define LCD_RETURNHOME 0x02 | |
#define LCD_ENTRYMODESET 0x04 | |
#define LCD_DISPLAYCONTROL 0x08 | |
#define LCD_CURSORSHIFT 0x10 | |
#define LCD_FUNCTIONSET 0x20 | |
#define LCD_SETCGRAMADDR 0x40 | |
#define LCD_SETDDRAMADDR 0x80 | |
// flags for display entry mode | |
#define LCD_ENTRYRIGHT 0x00 | |
#define LCD_ENTRYLEFT 0x02 | |
#define LCD_ENTRYSHIFTINCREMENT 0x01 | |
#define LCD_ENTRYSHIFTDECREMENT 0x00 | |
// flags for display on/off control | |
#define LCD_DISPLAYON 0x04 | |
#define LCD_DISPLAYOFF 0x00 | |
#define LCD_CURSORON 0x02 | |
#define LCD_CURSOROFF 0x00 | |
#define LCD_BLINKON 0x01 | |
#define LCD_BLINKOFF 0x00 | |
// flags for display/cursor shift | |
#define LCD_DISPLAYMOVE 0x08 | |
#define LCD_CURSORMOVE 0x00 | |
#define LCD_MOVERIGHT 0x04 | |
#define LCD_MOVELEFT 0x00 | |
// flags for function set | |
#define LCD_8BITMODE 0x10 | |
#define LCD_4BITMODE 0x00 | |
#define LCD_2LINE 0x08 | |
#define LCD_1LINE 0x00 | |
#define LCD_5x10DOTS 0x04 | |
#define LCD_5x8DOTS 0x00 | |
// flags for backlight control | |
#define LCD_BACKLIGHT 0x08 | |
#define LCD_NOBACKLIGHT 0x00 | |
// Enable bit | |
#define E 0x04 | |
// Read/write bit | |
#define RW 0x02 | |
// Register select bit | |
#define RS 0x01 | |
struct LCD { | |
int fd; | |
uint8_t addr; | |
int lines; | |
int chars; | |
int backlight; | |
int posx; | |
int posy; | |
}; | |
typedef enum { IR, DR } lcd_register; | |
typedef struct LCD lcd_t; | |
void lcd_init(lcd_t *lcd, char *dev, int addr, int chars, int lines); | |
void lcd_set_cursor(lcd_t *lcd, int chars, int lines); | |
void lcd_write_nibble(lcd_t *lcd, lcd_register reg, char data); | |
void lcd_write_instruction_high_nibble(lcd_t *lcd, uint8_t data); | |
void lcd_write_instruction(lcd_t *lcd, uint8_t data); | |
void lcd_write_data(lcd_t *lcd, uint8_t data); | |
void lcd_raw_write(lcd_t *lcd, char data); | |
void lcd_puts(lcd_t *lcd, char* str); | |
void lcd_putc(lcd_t *lcd, char c); | |
void lcd_clear_display(lcd_t *lcd); | |
void lcd_close(lcd_t *lcd); | |
int main(int argc, char** argv) { | |
lcd_t lcd; | |
lcd_init(&lcd, "/dev/iic1", 0x27, 16, 2); | |
for (int i = 1; i < argc; i++) { | |
lcd_set_cursor(&lcd, 0, i-1); | |
lcd_puts(&lcd, argv[i]); | |
} | |
lcd_close(&lcd); | |
return 0; | |
} | |
void lcd_init(lcd_t *lcd, char *dev, int addr, int chars, int lines) { | |
int fd = open(dev, O_RDWR); | |
if (fd == -1) { | |
err(1, "open device failed"); | |
} | |
lcd->fd = fd; | |
lcd->addr = addr; | |
lcd->chars = chars; | |
lcd->lines = lines; | |
lcd->backlight = 1; | |
lcd->posx = 0; | |
lcd->posy = 0; | |
lcd_write_instruction_high_nibble(lcd, LCD_FUNCTIONSET | LCD_8BITMODE); | |
usleep(5000); | |
lcd_write_instruction_high_nibble(lcd, LCD_FUNCTIONSET | LCD_8BITMODE); | |
usleep(100); | |
lcd_write_instruction_high_nibble(lcd, LCD_FUNCTIONSET | LCD_8BITMODE); | |
lcd_write_instruction_high_nibble(lcd, LCD_FUNCTIONSET | LCD_4BITMODE); | |
lcd_write_instruction(lcd, LCD_FUNCTIONSET | LCD_4BITMODE | LCD_2LINE); | |
lcd_write_instruction(lcd, LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF );// | LCD_BLINKON); | |
lcd_clear_display(lcd); | |
lcd_write_instruction(lcd, LCD_ENTRYMODESET | LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT); | |
} | |
void lcd_write_instruction_high_nibble(lcd_t *lcd, uint8_t data) { | |
uint8_t h = (data >> 4) & 0x0F; | |
lcd_write_nibble(lcd, IR, h); | |
usleep(37); | |
} | |
void lcd_write_instruction(lcd_t *lcd, uint8_t data) { | |
uint8_t h = (data >> 4) & 0x0F; | |
uint8_t l = data & 0x0F; | |
lcd_write_nibble(lcd, IR, h); | |
lcd_write_nibble(lcd, IR, l); | |
usleep(37); | |
} | |
void lcd_write_data(lcd_t *lcd, uint8_t data) { | |
uint8_t h = (data >> 4) & 0x0F; | |
uint8_t l = data & 0x0F; | |
lcd_write_nibble(lcd, DR, h); | |
lcd_write_nibble(lcd, DR, l); | |
usleep(41); | |
} | |
void lcd_write_nibble(lcd_t *lcd, lcd_register reg, char data) { | |
/* Shift the interesting data on the upper 4 bits (b7-b4) */ | |
data = (data << 4) & 0xF0; | |
/* Flip the RS bit if we write do data register */ | |
if (reg == DR) | |
data |= RS; | |
/* Keep the RW bit low, because we write */ | |
data = data | (RW & 0x00); | |
/* Flip the backlight bit */ | |
if (lcd->backlight) | |
data |= LCD_BACKLIGHT; | |
lcd_raw_write(lcd, data); | |
usleep(1); | |
/* Theoretically wait for tAS = 40ns, practically it's already elapsed */ | |
/* Raise the E signal... */ | |
lcd_raw_write(lcd, data | E); | |
/* Again, "wait" for pwEH = 230ns */ | |
usleep(1); | |
/* ...and let it fall to clock the data into the HD44780's register */ | |
lcd_raw_write(lcd, data); | |
/* And again, "wait" for about tCYC_E - pwEH = 270ns */ | |
usleep(1); | |
} | |
void lcd_raw_write(lcd_t *lcd, char data) { | |
uint8_t addr = lcd->addr << 1; | |
uint8_t cmd[1] = { data }; | |
struct iic_msg msgs = { addr | IIC_M_WR, IIC_M_WR, 1, cmd}; | |
struct iic_rdwr_data rwd = { &msgs, 1 }; | |
int e = ioctl(lcd->fd, I2CRDWR, &rwd); | |
if (e < 0) { | |
err(2, "i2c device write failed"); | |
} | |
} | |
void lcd_puts(lcd_t *lcd, char* str) { | |
int l = strlen(str); | |
for (int i = 0; i < l; i++) { | |
lcd_putc(lcd, str[i]); | |
} | |
} | |
int lines_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; | |
void lcd_set_cursor(lcd_t *lcd, int chars, int lines) { | |
if ( lines > lcd->lines ) { | |
lines = lcd->lines-1; // we count rows starting w/0 | |
} | |
lcd->posx = chars; | |
lcd->posy = lines; | |
lcd_write_instruction(lcd, LCD_SETDDRAMADDR | (chars + lines_offsets[lines])); | |
} | |
void lcd_putc(lcd_t *lcd, char c) { | |
lcd_write_data(lcd, c); | |
lcd->posx++; | |
if (lcd->posx == lcd->chars) { | |
lcd->posy = (lcd->posy + 1) % lcd->lines; | |
lcd->posx = 0; | |
lcd_write_instruction(lcd, LCD_SETDDRAMADDR | lines_offsets[lcd->posy]); | |
} | |
} | |
void lcd_clear_display(lcd_t *lcd) { | |
lcd_write_instruction(lcd, LCD_CLEARDISPLAY); | |
/* Wait for 1.64 ms because this one needs more time */ | |
usleep(1640); | |
/* | |
* CLEAR_DISPLAY instruction also returns cursor to home, | |
* so we need to update it locally. | |
*/ | |
lcd->posx = 0; | |
lcd->posy = 0; | |
} | |
void lcd_close(lcd_t *lcd) { | |
close(lcd->fd); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
all: pulse lcd | |
pulse: pulse.c | |
clang -lgpio -o $@ $< | |
lcd: lcd.c lcd.h lcd_const.h | |
clang -o $@ $< |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <err.h> | |
#include <stdio.h> | |
#include <unistd.h> | |
#include <libgpio.h> | |
#include <time.h> | |
#include <stdlib.h> | |
int main(int argc, char** argv) { | |
if (argc < 3) { | |
err(1, "%s <gpio> <pin>", argv[0]); | |
} | |
int gpio = atoi(argv[1]); | |
int pin = atoi(argv[2]); | |
gpio_handle_t h = gpio_open(gpio); | |
if (h == GPIO_VALUE_INVALID) | |
err(1, "gpio_open failed"); | |
gpio_pin_input(h, pin); | |
gpio_value_t v; | |
gpio_value_t lv; | |
while (true) { | |
usleep(1000); | |
v = gpio_pin_get(h, pin); | |
if (lv != v) { | |
if (v == 0) { | |
printf("."); | |
fflush(stdout); | |
} | |
lv = v; | |
} | |
} | |
gpio_close(h); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FreeBSD usage of I2C & GPIO on BeagleBoneBlack: FreeBSD beaglebone 13.1-RELEASE FreeBSD 13.1-RELEASE releng/13.1-n250148-fc952ac2212 GENERIC arm