Skip to content

Commit 602f48b

Browse files
Added support for ST7032i controller (#6)
Added support for the ST7032i LCD display controller. In doing so, refactored code to improve ability to add support for more controllers.
1 parent 68159b1 commit 602f48b

14 files changed

+1773
-921
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ Cargo.lock
44

55
# MacOS
66
.DS_Store
7+
8+
# local dev
9+
documentation/

CHANGELOG.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
## [0.5.0] - 2025-02-16
6+
* Refactored code base to make it easier to add support for new character display controllers which minmal duplication of code.
7+
* Added support for the ST7032i conrtroller
8+
59
## [0.4.0] - 2024-11-24
610
* Completely refactored code to enable different controller types.
711
* Improved error handling and test coverage.
@@ -23,7 +27,8 @@
2327
## 0.1.0
2428
Initial release. Support for both Generic PCF8574T I2C and Adafruit Backpack character display adapters.
2529

26-
[Unreleased]: https://github.com/michaelkamprath/bespokeasm/compare/v0.4.0...HEAD
30+
[Unreleased]: https://github.com/michaelkamprath/bespokeasm/compare/v0.5.0...HEAD
31+
[0.5.0]: https://github.com/michaelkamprath/bespokeasm/compare/v0.4.0...v0.5.0
2732
[0.4.0]: https://github.com/michaelkamprath/bespokeasm/compare/v0.3.0...v0.4.0
2833
[0.3.0]: https://github.com/michaelkamprath/bespokeasm/compare/v0.2.1...v0.3.0
2934
[0.2.1]: https://github.com/michaelkamprath/bespokeasm/compare/v0.2.0...v0.2.1

Cargo.toml

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "i2c-character-display"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
edition = "2021"
55
description = "Driver for HD44780-based character displays connected via a I2C adapter"
66
license = "MIT"
@@ -23,10 +23,9 @@ bitfield = "0.17"
2323
defmt = { version = "0.3", optional = true }
2424
ufmt = {version = "0.2", optional = true}
2525

26-
2726
[features]
2827
defmt = ["dep:defmt", "embedded-hal/defmt-03"]
2928
ufmt = ["dep:ufmt"]
3029

3130
[dev-dependencies]
32-
embedded-hal-mock = "0.11"
31+
embedded-hal-mock = "0.11"

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ in an embedded, `no_std` environment. A number of I2C interfaces are supported:
1414
This library supports that configuration, though it would be straightforward to add support for other pin configurations.
1515
- **AiP31068** - This is a character display controller with a built-in I2C support. The command set is similar to the HD44780, but the controller
1616
operates in 8-bit mode and is initialized differently. Examples of displays that use this controller include the [Surenoo SLC1602O](https://www.surenoo.com/products/8109143).
17+
- **ST7032i** - This is an I2C character display controller used with LCD displays. It is similar to the HD44780, but with some differences in the command set.
18+
Examples of displays that use this controller include the [Surenoo SLC1602K3](https://www.surenoo.com/collections/81733622/products/8131705).
1719

1820
Key features include:
1921
- Convenient high-level API for controlling many types of character display
@@ -55,6 +57,8 @@ let mut lcd = CharacterDisplayPCF8574T::new(i2c, LcdDisplayType::Lcd16x2, delay)
5557
let mut lcd = CharacterDisplayDualHD44780::new(i2c, LcdDisplayType::Lcd40x4, delay);
5658
// Character display with the AiP31068 controller
5759
let mut lcd = CharacterDisplayAIP31068::new(i2c, LcdDisplayType::Lcd16x2, delay);
60+
// Character display with the ST7032i controller
61+
let mut lcd = CharacterDisplayST7032i::new(i2c, LcdDisplayType::Lcd16x2, delay);
5862
```
5963
When creating the display object, you can choose the display type from the `LcdDisplayType` enum. The display type should match the physical
6064
display you are using. This display type configures the number of rows and columns, and the internal row offsets for the display.

src/driver.rs

+82-46
Original file line numberDiff line numberDiff line change
@@ -1,134 +1,170 @@
1-
pub mod hd44780;
21
pub mod aip31068;
2+
pub mod hd44780;
3+
pub mod st7032i;
4+
pub mod standard;
35

46
use embedded_hal::{delay::DelayNs, i2c};
57

6-
use crate::{CharacterDisplayError, DeviceSetupConfig};
8+
use crate::{CharacterDisplayError, DeviceSetupConfig, LcdDisplayType};
79

8-
pub trait DriverTrait<I2C, DELAY>: Default
10+
/// Trait for device hardware implementations. Embodies the hardware-specific
11+
/// functionality of the device driver IC. The trait is intended to be implemented
12+
/// for the specific device driver ICs.
13+
pub trait DeviceHardwareTrait<I2C, DELAY>
914
where
1015
I2C: i2c::I2c,
1116
DELAY: DelayNs,
1217
{
18+
fn new(config: DeviceSetupConfig<I2C, DELAY>) -> Self;
1319
/// returns the default I2C address for the device
1420
fn default_i2c_address() -> u8;
1521

1622
/// returns whether reads are supported by the device
1723
fn supports_reads() -> bool;
1824

19-
/// Initialize the display
20-
fn init(
25+
/// returns LCD type
26+
fn lcd_type(&self) -> LcdDisplayType;
27+
28+
/// returns configured i2c address
29+
fn i2c_address(&self) -> u8;
30+
31+
/// return a immutable reference to the delay object
32+
fn delay(&mut self) -> &mut DELAY;
33+
34+
/// returns the i2c object. mostly used for testing
35+
fn i2c(&mut self) -> &mut I2C;
36+
37+
/// initializes the device hardware. On `Ok`, returns the initial configuration
38+
/// of the device. The configuration is a tuple of three bytes:
39+
/// (display_function, display_control, display_mode)
40+
fn init(&mut self) -> Result<(u8, u8, u8), CharacterDisplayError<I2C>>;
41+
42+
fn write_bytes(
2143
&mut self,
22-
device: &mut DeviceSetupConfig<I2C, DELAY>,
44+
rs_setting: bool,
45+
data: &[u8],
46+
) -> Result<(), CharacterDisplayError<I2C>>;
47+
}
48+
49+
/// Trait for display actions. Embodies the display commnands that can be performed on the device.
50+
/// Works with the `DeviceHardwareTrait` to perform the actions on the device to effect the desire
51+
/// display operation.
52+
pub trait DisplayActionsTrait<I2C, DELAY, DEVICE>: Default
53+
where
54+
I2C: i2c::I2c,
55+
DELAY: DelayNs,
56+
DEVICE: DeviceHardwareTrait<I2C, DELAY>,
57+
{
58+
/// Initialize the display state. Intended to be called once after the device is initialized
59+
/// and before any other operations are performed. The three parameters are the initial values
60+
/// and are recieved from the `DeviceHardwareTrait::init` method of the device.
61+
fn init_display_state(
62+
&mut self,
63+
display_function: u8,
64+
display_control: u8,
65+
display_mode: u8,
2366
) -> Result<(), CharacterDisplayError<I2C>>;
2467

2568
/// Clear the display
26-
fn clear(
27-
&mut self,
28-
device: &mut DeviceSetupConfig<I2C, DELAY>,
29-
) -> Result<(), CharacterDisplayError<I2C>>;
69+
fn clear(&mut self, device: &mut DEVICE) -> Result<(), CharacterDisplayError<I2C>>;
3070

3171
/// Set the cursor to the home position.
32-
fn home(
33-
&mut self,
34-
device: &mut DeviceSetupConfig<I2C, DELAY>,
35-
) -> Result<(), CharacterDisplayError<I2C>>;
72+
fn home(&mut self, device: &mut DEVICE) -> Result<(), CharacterDisplayError<I2C>>;
3673

3774
/// Set the cursor position at specified column and row. Columns and rows are zero-indexed.
3875
fn set_cursor(
3976
&mut self,
40-
device: &mut DeviceSetupConfig<I2C, DELAY>,
77+
device: &mut DEVICE,
4178
col: u8,
4279
row: u8,
4380
) -> Result<(), CharacterDisplayError<I2C>>;
4481

4582
/// Set the cursor visibility.
4683
fn show_cursor(
4784
&mut self,
48-
device: &mut DeviceSetupConfig<I2C, DELAY>,
85+
device: &mut DEVICE,
4986
show_cursor: bool,
5087
) -> Result<(), CharacterDisplayError<I2C>>;
5188

5289
/// Set the cursor blinking.
5390
fn blink_cursor(
5491
&mut self,
55-
device: &mut DeviceSetupConfig<I2C, DELAY>,
92+
device: &mut DEVICE,
5693
blink_cursor: bool,
5794
) -> Result<(), CharacterDisplayError<I2C>>;
5895

5996
/// Set the display visibility.
6097
fn show_display(
6198
&mut self,
62-
device: &mut DeviceSetupConfig<I2C, DELAY>,
99+
device: &mut DEVICE,
63100
show_display: bool,
64101
) -> Result<(), CharacterDisplayError<I2C>>;
65102

66103
/// Scroll display left.
67-
fn scroll_left(
68-
&mut self,
69-
device: &mut DeviceSetupConfig<I2C, DELAY>,
70-
) -> Result<(), CharacterDisplayError<I2C>>;
104+
fn scroll_left(&mut self, device: &mut DEVICE) -> Result<(), CharacterDisplayError<I2C>>;
71105

72106
/// Scroll display right.
73-
fn scroll_right(
74-
&mut self,
75-
device: &mut DeviceSetupConfig<I2C, DELAY>,
76-
) -> Result<(), CharacterDisplayError<I2C>>;
107+
fn scroll_right(&mut self, device: &mut DEVICE) -> Result<(), CharacterDisplayError<I2C>>;
77108

78109
/// Set the text flow direction to left to right.
79-
fn left_to_right(
80-
&mut self,
81-
device: &mut DeviceSetupConfig<I2C, DELAY>,
82-
) -> Result<(), CharacterDisplayError<I2C>>;
110+
fn left_to_right(&mut self, device: &mut DEVICE) -> Result<(), CharacterDisplayError<I2C>>;
83111

84112
/// Set the text flow direction to right to left.
85-
fn right_to_left(
86-
&mut self,
87-
device: &mut DeviceSetupConfig<I2C, DELAY>,
88-
) -> Result<(), CharacterDisplayError<I2C>>;
113+
fn right_to_left(&mut self, device: &mut DEVICE) -> Result<(), CharacterDisplayError<I2C>>;
89114

90115
/// Set the auto scroll mode.
91116
fn autoscroll(
92117
&mut self,
93-
device: &mut DeviceSetupConfig<I2C, DELAY>,
118+
device: &mut DEVICE,
94119
autoscroll: bool,
95120
) -> Result<(), CharacterDisplayError<I2C>>;
96121

97122
/// Prints a string to the LCD at the current cursor position of the active device.
98-
fn print(
99-
&mut self,
100-
device: &mut DeviceSetupConfig<I2C, DELAY>,
101-
text: &str,
102-
) -> Result<(), CharacterDisplayError<I2C>>;
123+
fn print(&mut self, device: &mut DEVICE, text: &str) -> Result<(), CharacterDisplayError<I2C>>;
103124

104125
/// Sets the backlight on or off
105126
fn backlight(
106127
&mut self,
107-
device: &mut DeviceSetupConfig<I2C, DELAY>,
128+
device: &mut DEVICE,
108129
on: bool,
109130
) -> Result<(), CharacterDisplayError<I2C>>;
110131

111132
/// creates a new custom character
112133
fn create_char(
113134
&mut self,
114-
device: &mut DeviceSetupConfig<I2C, DELAY>,
135+
device: &mut DEVICE,
115136
location: u8,
116137
charmap: [u8; 8],
117138
) -> Result<(), CharacterDisplayError<I2C>>;
118139

119140
/// read bytes from the active controller of the device. The size of the buffer is the number of bytes to read.
120141
fn read_device_data(
121142
&self,
122-
_device: &mut DeviceSetupConfig<I2C, DELAY>,
143+
_device: &mut DEVICE,
123144
_buffer: &mut [u8],
124145
) -> Result<(), CharacterDisplayError<I2C>> {
125-
unimplemented!("Reads are not supported for device");
146+
#[cfg(feature = "defmt")]
147+
defmt::warn!("Reading data is not supported on this display");
148+
Err(CharacterDisplayError::UnsupportedOperation)
126149
}
127150

128151
fn read_address_counter(
129152
&mut self,
130-
_device: &mut DeviceSetupConfig<I2C, DELAY>,
153+
_device: &mut DEVICE,
131154
) -> Result<u8, CharacterDisplayError<I2C>> {
132-
unimplemented!("Reads are not supported for device");
155+
#[cfg(feature = "defmt")]
156+
defmt::warn!("Reading the address counter is not supported on this display");
157+
Err(CharacterDisplayError::UnsupportedOperation)
158+
}
159+
160+
/// Set the contrast of the display. This is not supported by all devices.
161+
fn set_contrast(
162+
&mut self,
163+
_device: &mut DEVICE,
164+
_contrast: u8,
165+
) -> Result<(), CharacterDisplayError<I2C>> {
166+
#[cfg(feature = "defmt")]
167+
defmt::warn!("Setting contrast is not supported on this display");
168+
Err(CharacterDisplayError::UnsupportedOperation)
133169
}
134170
}

0 commit comments

Comments
 (0)