Skip to content

Instantly share code, notes, and snippets.

@TG9541

TG9541/W28_IR_RC.md

Last active Jan 8, 2021
Embed
What would you like to do?
STM8 eForth: IR Remote Control for an RGBW LED Bulb

STM8 eForth: IR Remote Control for an RGBW LED Bulb

Today, IR remote control is by far the cheapest option for consumer electronics. I've long had the idea that Forth is ideal for scripting IR remote-controlled devices, and I used the light bulb at my desk to learn how to do that with STM8 eForth.

LED lamps of relatively high quality with a combination of white LED and RGB LEDs have a remarkable low price tag: the set below costs no more than a regular white LED lamp. In my experience service life seems to be much better, maybe due to the better power supply with µC PWM control and the occassional colorful illumination is certainly a plus.

image

The rock bottom price of the W28 remote control shows - it's just a bit of plastics with the cheapest film keypad possible.

With the help of an IR receiver (a rather dated SHARP GP1UD272XK) connected to PulseView I found out that the protocol is a "NEC" variant:

image

The "W28" remote control uses the NEC address "0" (regular protocol, i.e. $00 followed by $FF) and it uses the "command - repeat" protocol. The commands are as follows:

W28 Keys Column 1 Column 2 Column 3 Column 4
Row 1 5 bright 4 dim 6 off 7 on
Row 2 9 red 8 green 10 blue 11 white
Row 3 13 red1 12 green1 14 blue1 15 f-col
Row 4 21 orange 20 cyan 22 purple 23 r-col
Row 5 25 orange1 24 petrol 26 purple1 27 flash
Row 6 17 yellow 16 teal 18 pink 19 s-col

It's not likely that these bulbs implement any other codes (other people have looked in vain).

I decided to use a timer to produce the 38kHz carrier with the STM8 TIM1 Capture/Compare PWM function. A rather generic TIM1 "update event" ISR creates the sequence of "mark" and "space" required by the NEC protocol. This "engine" can be easily changed to serve other protocols.

The code, using the current development version of STM8 eForth is here:

\ "W28" IR remote control with NEC protocol for a Chinese "RGBW" LED lamp
\ using an STM8S Low Density device (e.g. STM8S103)
\ IR LED cathode connected to PC3 (TIM1_CH3)

\res MCU: STM8S103

\res export TIM1_CR1 TIM1_IER TIM1_SR1 TIM1_BKR TIM1_CCER2
\res export TIM1_ARRH TIM1_CCMR3 TIM1_CCR3H INT_TIM1

\ TIM1 bit constants
0 CONSTANT UIE
0 CONSTANT CC3E
7 CONSTANT MOE

#require :NVM
#require ]B!
#require >REL

\ ( carry-flag ) IF with relative addressing
: ]CFIF ( -- ) $24 C, ] >REL ;  \ JRNC rel

NVM

VARIABLE mrk    \ mark duration in 1/38kHz pulses
VARIABLE spc    \ spc duration in 1/38kHz pulses
VARIABLE bcnt   \ bit counter
VARIABLE sreg 2 ALLOT  \ IR send register for ISR

\ IR-NEC pattern ISR triggered by TIM1 Update Event
:NVM
  SAVEC
  [ 0 TIM1_SR1 UIE ]B!  \ clear interrupt

  mrk @ ?DUP IF
    [  1 TIM1_CCER2 CC3E ]B!  \ mark: enable 38 kHz PWM
    1- mrk !
  ELSE
    [  0 TIM1_CCER2 CC3E ]B!  \ space: disable 38 kHz PWM 
    spc @ ?DUP IF
      1- spc !
    ELSE
      bcnt @ ?DUP IF
        1- bcnt !
        24 mrk !  [  \ 0.65 ms mark
          \ rotate right bit pattern - NEC protocol is LSB first
          $36 C, sreg 3 + C,  \ RRC  sreg+3 ; (zero page addressing)
          $36 C, sreg 2 + C,  \ RRC  sreg+2
          $36 C, sreg 1 + C,  \ RRC  sreg+1)
          $36 C, sreg C,      \ RRC  sreg
        ]CFIF
          60 spc !   \ carry flag set: spc 1.6ms
        ELSE
          19 spc !   \ carry flag clr: spc 0.5ms
        THEN
      THEN
    THEN
  THEN
  IRET
[ OVERT ( xt ) INT_TIM1 !


\ Init TIM1 for 38kHz ticker interrupt and 50 duty PWM output
: init ( -- )
  $60 TIM1_CCMR3 C!        \ PWM mode 1
  421 TIM1_ARRH 2C!        \ 38kHz @ 16MHz HSI
  210 TIM1_CCR3H 2C!       \ 50% duty cycle
  [ 1 TIM1_BKR MOE ]B!     \ main output enable
  [ 1 TIM1_CCER2 CC3E ]B!  \ Capture Compare output enable (CC3E)
  [ 1 TIM1_CR1 UIE ]B!     \ enable timer
  [ 1 TIM1_IER UIE ]B!     \ enable timer update interupt
;

\ turn c into MSB, complement LSB
: NECinv ( c - n ) [
  \ 256 OVER * SWAP NOT 255 AND OR
  $E601 ,         \ LD   A,(1,X)
  $6301 ,         \ CPL  (1,X)
  $F7 C,          \ LD   (X),A
] ;

\ send NEC-IR code with W28 remote control timing
: ir ( c -- )
  [ 0 TIM1_CR1 UIE ]B!  \ disable timer interrupt
  0 NECinv sreg !       \ the W28 remote control uses address 0
  ( c ) NECinv sreg 2+ !
  342 mrk !             \ 9ms AGC pulse (first mark)
  171 spc !             \ 4.5ms leader pause (first space)
  33 bcnt !             \ NEC: 33 mark/space events
  [ 1 TIM1_CR1 UIE ]B!  \ enable timer interrupt
;

\ wait until the IR code transmission has ended
: irw ( -- )
  BEGIN bcnt @ 0= UNTIL
;

RAM

\\ Example:

\ -----------|----------|---------|----------
\   5 bright | 4 dim    | 6 off   | 7 on
\ -----------|----------|---------|----------
\   9 red    | 8 green  |10 blue  |11 white
\ -----------|----------|---------|----------
\  13 red1   |12 green1 |14 blue1 |15 cf-col
\ -----------|----------|---------|----------
\  21 red2   |20 green2 |22 blue2 |23 cr-col
\ -----------|----------|---------|----------
\  25 red3   |24 green3 |26 blue3 |27 flash
\ -----------|----------|---------|----------
\  17 red4   |16 green4 |18 blue4 |19 cs-col
\ -----------|----------|---------|----------

7 ir  \ lamp on
10 ir irw 11 ir  \ flash blue, then white
6 ir  \ lamp off
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment