Skip to content

Commit

Permalink
Support TM1628-based LED display module
Browse files Browse the repository at this point in the history
... connected via three-wire bus; clock & data lines shared with I²C
  • Loading branch information
OlekMazur committed May 12, 2024
1 parent 1267023 commit a0906ee
Show file tree
Hide file tree
Showing 13 changed files with 628 additions and 134 deletions.
67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Supported peripheral devices
| I²C | AT24C02 | Configuration storage |
| I²C | TMP75 | Temperature measurement & reporting |
| I²C | [7-seg 4-digit LED display module] | Clock & temperature display |
| SPI | HT-2261LED-V1.0 | Clock & temperature display |

Principle of operation
----------------------
Expand Down Expand Up @@ -341,7 +342,10 @@ Supervisor must wait for response before issuing next command.
| \<space> | Reset watchdog | \<space> |
| bxx | Read RAM byte at xx (hex) | yy (byte from RAM, hex) |
| Bxx | Write byte xx (hex) to RAM at the address last used with **b** command (above) | @ |
| E | Get address of configuration EEPROM on the I²C bus | xx (value of I2C_EEPROM_WR), or **!** if it's just A0 = the default |
| E | Get address of configuration EEPROM on the I²C bus | xx (value of I2C_EEPROM_WR), or **?** if it's just A0 = the default |
| ( | Send SPI *START* | @ |
| ) | Send SPI *STOP* | @ |
| +xx | Send byte xx (hex) to SPI | @ |

It is recommended that supervisor resets watchdog by sending space
after each incoming report. Not doing this for `WATCHDOG_MAX` = 22 times
Expand Down Expand Up @@ -458,6 +462,11 @@ Test [7-seg 4-digit LED display module]:
IW76W09S
```

Turn on **HT-2261LED-V1.0** display module and show something on it:
```
(+8F)(+C0+73+73+3E+3E+73+73+77+77+00)
```

Set RTC to Wednesday (3) noon (12:00) and reset *clock settings index*
(assuming RAM locations as in the *Example address* above):
```
Expand Down Expand Up @@ -490,6 +499,30 @@ Address (for writing) of [7-seg 4-digit LED display module] on the I²C bus.

If undefined, there is no display module support, what saves 201 B.

### SPI_STB, SPI_DIO, SPI_CLK
Ports where three-wire bus is connected to.
DIO and CLK may be shared with SDA and SCL.
If undefined, there is no three-wire bus support.

### DISPLAY_TM1628
If defined, there is TM1628-compatible display connected via SPI
(e.g. a **HT-2261LED-V1.0** board).

![HT-2261LED]

### DISPLAY_SWITCH_PORT
Port where a switch controlling the display is connected.
The switch should connect given port to ground.

If undefined, there is no such switch and the display is turned on
by default. It can be turned off/on via UART by manipulating `flag_display_on`
with **b** and **B** commands only.

### DISPLAY_SWITCH_NEGATIVE
If defined, low state of DISPLAY_SWITCH_PORT turns display on.

If undefined (default), high state of DISPLAY_SWITCH_PORT turns display on.

### OW_PARASITE
If defined, then 1-wire bus is parasite-powered
(OW_PWR=0 enables strong pull-up on the bus).
Expand Down Expand Up @@ -611,6 +644,34 @@ that contrary to AT89C4051 that part misses brown-out reset.

### Example 2

Let's use chassis of some old STB along with its LED display module.

![HD-527]

```
CONSERVATIVE_CONTROL equ 1
CONTROL_NEGATIVE equ 1
RELAY_PORT equ P1
OW_PWR equ P3.4
OW_PARASITE equ 21
OW_DQ equ P3.5
SDA equ P3.3
SCL equ P3.2
SPI_STB equ P3.7
SPI_DIO equ P3.3
SPI_CLK equ P3.2
I2C_EEPROM_WR equ 10100000b
I2C_TEMP_WR equ 10010000b
DISPLAY_TM1628 equ 1
DISPLAY_SWITCH_PORT equ P1.0
TUNE_1WIRE equ 1
AT89C4051 equ 1
```

Here we need AT89C4051 since the firmware is 2425 B.

### Example 3

Instead of opto-isolated relay module we may use ULN2003 + up to 7 relays.

![PCB2] ![PCB3] ![PCB4] ![PCB5]
Expand All @@ -630,7 +691,7 @@ TUNE_1WIRE equ 1

2041 B this time.

### Example 3
### Example 4

No parasite power, but capable of resetting DS1821 to 1-wire mode
from standalone thermostat mode (using **t** command).
Expand Down Expand Up @@ -670,12 +731,14 @@ along with Thermostat Firmware. If not, see <https://www.gnu.org/licenses/>.

[7-seg 4-digit LED display module]: https://www.elektroda.pl/rtvforum/topic117391.html
[Display]: img/LED_module.jpg
[HT-2261LED]: img/HT-2261LED-V1.0.jpg
[PCB top]: img/PCB_A.jpg
[PCB bottom]: img/PCB_R.jpg
[Relays]: img/relays.jpg
[PCB2]: img/PCB2_A.jpg
[PCB3]: img/PCB3_A.jpg
[PCB4]: img/PCB4_A.jpg
[PCB5]: img/PCB5_A.jpg
[HD-527]: img/HD-527.jpg
[GNU General Public License]: LICENSE.md
[asem-51]: http://plit.de/asem-51
145 changes: 65 additions & 80 deletions control.asm
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
; You should have received a copy of the GNU General Public License
; along with Thermostat Firmware. If not, see <https://www.gnu.org/licenses/>.
;
; Copyright (c) 2018, 2021 Aleksander Mazur
; Copyright (c) 2018, 2021, 2022 Aleksander Mazur
;
; Logika sterowania przekaźnikami
; Używa procedur obsługi EEPROM z i2c_eeprom.asm
; Procedury używają zmiennych control_*

;
; Schemat wywołań:
; control_init_rtc
; control_watchdog
Expand Down Expand Up @@ -68,10 +68,35 @@ control_watchdog_ret:
; Inicjalizuje maski sterowania i realizuje program zegarowy
; Niszczy A, B, C, R1, R6, R7, F0
control_init_rtc:
ifdef I2C_DISPLAY_WR
ifdef I2C_SPI_DISPLAY
clr flag_display_used
clr flag_display_missing
endif
clr flag_display_found_idx
jnb flag_display_on, control_skip_display
; szukamy funkcji z włączoną flagą ctl_flag_display
; o numerze większym lub równym display_func_idx
acall control_iterate_functions
setb C
subb A, display_func_idx
jc control_skip_display
inc A
mov R0, A ; R0 = liczba pozostałych funkcji w EEPROM (> 0)
mov R3, display_func_idx ; R3 = bieżący indeks funkcji liczony od 0
control_find_display_loop:
acall control_read_flags
jc control_skip_display
acall i2c_shin
; A = flagi
acall eeprom_read_stop
jnb ACC.5, control_find_display_next ; ACC.5 = ctl_flag_display
; znaleźliśmy
mov display_func_idx, R3
setb flag_display_found_idx
sjmp control_skip_display
control_find_display_next:
inc R3
djnz R0, control_find_display_loop
control_skip_display:
endif ;I2C_SPI_DISPLAY
; zerujemy maski sterowania
clr A
mov R1, #control_mask_start
Expand Down Expand Up @@ -140,24 +165,14 @@ control_ret2:
; Niszczy A, B, C, R0, R1, R2(CRC), R3, R6, R7
control_missing:
acall control_iterate_functions
jz control_ret2 ; nie ma żadnych funkcji w EEPROM lub wystąpił błąd
jz control_missing2 ; nie ma żadnych funkcji w EEPROM lub wystąpił błąd
mov R0, A ; R0 = liczba funkcji w EEPROM (>0)
mov R3, #0 ; R3 = bieżący indeks funkcji liczony od 0
ifdef I2C_DISPLAY_WR
; zaczynamy szukanie następnej funkcji z włączoną flagą ctl_flag_display
; o numerze większym od obecnej (display_func_curr)
mov A, display_func_curr
inc A
mov display_func_next, A
clr flag_display_found_next
endif
control_missing_loop:
ifndef I2C_DISPLAY_WR
acall control_get_used_ptr
anl A, @R1
; 0 - funkcja nie została użyta
jnz control_missing_next
endif
; czytamy flagi
acall control_read_flags
jc control_missing_next
Expand All @@ -169,31 +184,6 @@ endif
orl control_mask_all_used, A ; nie powinno zaszkodzić nawet, jeśli funkcja była użyta
acall eeprom_read_stop
mov A, R2
ifdef I2C_DISPLAY_WR
jnb ACC.5, control_missing_no_display ; C = ACC.5 (ctl_flag_display)
; wyświetlanie temperatury wynikającej z tej funkcji jest włączone
jb flag_display_found_next, control_missing_no_display
; czy R3 >= display_func_next?
mov A, R3
cjne A, display_func_next, control_missing_cont
control_missing_cont:
jc control_missing_no_display
; znaleźliśmy nowy numer
mov display_func_next, A
setb flag_display_found_next
control_missing_no_display:
acall control_get_used_ptr
anl A, @R1
; 0 - funkcja nie została użyta
jnz control_missing_next
mov A, R3
cjne A, display_func_curr, control_missing_another
; mieliśmy właśnie wyświetlić tę temperaturę, ale brakuje czujnika
; być może wypadałoby jeszcze sprawdzić, czy ctl_flag_display jest ustawiona...
setb flag_display_missing
control_missing_another:
mov A, R2
endif
mov C, ACC.6 ; C = ACC.6 (ctl_flag_critical)
; obliczamy maskę sterowania pośredniego
acall control_calc_direct_mask
Expand All @@ -211,43 +201,37 @@ endif
control_missing_next:
inc R3
djnz R0, control_missing_loop
ifdef I2C_DISPLAY_WR
jb flag_display_found_next, control_missing_next_ok
; jeśli nie znalazła się następna funkcja z włączoną flagą ctl_flag_display,
; to następnym razem skanujemy od początku
mov display_func_next, #-1
control_missing_next_ok:
; jeśli flag_display_used=1, to znaczy, że wysłaliśmy już temperaturę na wyświetlacz
; jeśli flag_display_missing=1, to znaczy, że brakuje temperatury czujnika,
; którego temperatura miała teraz znaleźć się na wyświetlaczu
jb flag_display_used, control_display_used
jb flag_display_missing, control_display_used
; jeśli obie flagi są 0, to pokazujemy zegarek
control_missing2:
ifdef I2C_SPI_DISPLAY
jb flag_display_on, control_display_cont
; następnym razem zegar, na razie wyświetlacz wyłączony
mov display_func_idx, #-1
ret
control_display_cont:
jnb flag_display_found_idx, control_display_clock
; flag_display_found_idx ustawiona -> temperatura na wyświetlaczu
inc display_func_idx
jb flag_display_used, control_display_finish
; lub informujemy, że temperatury nie ma
bcall display_missing
control_display_finish:
; opóźnienie między rozkazami wysyłanymi do wyświetlacza (R0 = 0)
djnz R0, $
; zapalamy wyświetlacz na pół gwizdka
ifdef TUNE_1WIRE
mov A, display_intensity
else
mov A, #display_intensity_def
endif
bjmp display_dim
control_display_clock:
; flag_display_found_idx wyczyszczona -> zegar na wyświetlaczu
bcall display_clock
control_display_delay:
setb flag_display_used
; wyświetlacz nie reaguje na ustawianie jasności wysyłane od razu;
; po sukcesie i2c_shout R7=0 i wtedy opóźnienie wynosi
; 256*(12+24)/22118400 = 5/12 ms
djnz R7, control_display_delay
control_display_used:
clr A
jnb flag_display_used, control_display_unused
; jeśli mamy coś na wyświetlaczu (temperaturę albo zegarek),
; to włączamy wyświetlacz na 2/4, w przeciwnym razie
; - kiedy brakuje wszystkich czujników, których temperaturę
; mieliśmy wyświetlać - wyłączamy wyświetlacz
mov A, #2
control_display_unused:
; A = flag_display_used ? 3 (3/4 jasności) : 0 (wygaś)
bcall display_dim
mov display_func_curr, display_func_next
jnb flag_display_missing, control_ret2
; jeszcze piśnięcie, jeśli nie wyświetliliśmy nic z powodu braku czujnika
bjmp display_beep
mov display_func_idx, #0
sjmp control_display_finish
else
ret
endif
endif ;I2C_SPI_DISPLAY

ifndef SKIP_CTRL_TEMP
;-----------------------------------------------------------
Expand Down Expand Up @@ -319,12 +303,13 @@ control_temperature_known:
push ACC ; maska bezpośredniego sterowania przekaźnikami - na stos
; musimy przerwać odczyt, żeby pobrać dane z właściwego programu dobowego
acall eeprom_read_stop
ifdef I2C_DISPLAY_WR
ifdef I2C_SPI_DISPLAY
jnb flag_display_on, control_display_handled
mov A, R2
jnb ACC.5, control_temperature_displayed ; ctl_flag_display
jnb ACC.5, control_display_handled ; ctl_flag_display
bcall display_temperature
control_temperature_displayed:
endif
control_display_handled:
endif ;I2C_SPI_DISPLAY
acall control_get_function_address
add A, #ctl_offset_f_daily
acall control_read_daily_program
Expand Down Expand Up @@ -756,7 +741,7 @@ control_temp_diff:
control_ret7:
ret

endif
endif ;SKIP_CTRL_TEMP

;-----------------------------------------------------------
; Odczytuje z EEPROM 3 bajty do control_settings_block
Expand Down
Loading

0 comments on commit a0906ee

Please sign in to comment.