Wednesday 8 July 2020

Flashed Before My Eyes: Flashing firmware of WiFi 2-Channel Relay Board Part 2 of 2


Nu-Link programmer (bottom) with LC Technology's WiFi Relay Board

In Part 1, we encountered a 'Device ID' problem reading the N76E003AT20 CPU in the LC Technology WiFi Relay Board. The CPU appeared to be responding to the programmer's queries, so I checked the nuvoprog source code. In the file protocol/commands.go was the code to check for Device ID:

type DeviceID uint32
const (
        // N76E003, Observed in trace
        //
        // Matches IAP registers:
        //   0x00CCDDDD where
        //              CC   = Company ID
        //              DDDD = Device ID
        DeviceN76E003 = 0xDA3650
)

And since my relay board's N76E003 was returning 0xff3650, I changed it to 

type DeviceID uint32
const (
        // N76E003, Observed in trace
        //
        // Matches IAP registers:
        //   0x00CCDDDD where
        //              CC   = Company ID
        //              DDDD = Device ID
        // DeviceN76E003 = 0xDA3650
        DeviceN76E003 = 0xFF3650
)

Now remember to put your nuvoton directory into /root/go/ for the build only works for that directory listed in the environmant variable GOPATH:

# go env GOPATH
/root/go

# go build

And indeed there is a new nuvoprog (check the timestamp):
# ls -l
total 5224
drwxr-xr-x 2 root root    4096 Jul  6 17:15 cmd
drwxr-xr-x 2 root root    4096 Jul  6 17:15 ihex
-rw-r--r-- 1 root root   11358 Jul  6 17:15 LICENSE
-rw-r--r-- 1 root root     688 Jul  6 17:15 main.go
drwxr-xr-x 2 root root    4096 Jul  6 17:15 misc
-rwxr-xr-x 1 root root 5306088 Jul  7 15:46 nuvoprog
drwxr-xr-x 2 root root    4096 Jul  7 15:44 protocol
-rw-r--r-- 1 root root    2812 Jul  6 17:15 README.md
drwxr-xr-x 4 root root    4096 Jul  6 17:15 target

And now the programmer reads back properly:
# ./nuvoprog read -t n76e003  2relay_readback_good.ihx -v
.
.
.
2020/07/07 15:46:45 Performing reset {None (NuLink) Disconnect Ext Mode}
2020/07/07 15:46:45 >  0c10e2000000050000000400000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/07 15:46:45 <  0c04e2000000fffffffffffffffffffffffffffffffffffffffffffff
fffffffffff000046662915699c03b4c74319896b6b8896664ef446d10e91c0d10a904c
2020/07/07 15:46:45 OK

Now despite a working relay board the program file read back is actually blank:

# head 2relay_readback_good.ihx
:020000040003F7
:08000000FDFFFFFFFFFFFFFF02
:020000040000FA
:20000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:20004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:20006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:20008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
:2000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:2000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40

A check of the relay CPU configuration revealed the cause: it has been locked:

# ./nuvoprog config decode -t n76e003 -i 2relay_readback_good.ihx
{
    "boot_select": "aprom",
    "pwm_enabled_during_ocd": false,
    "ocd_enabled": false,
    "reset_pin_disabled": false,
    "locked": true,
    "ldrom_size": "0kb",
    "bod_disabled": false,
    "bod_voltage": "2v2",
    "iap_enabled_in_brownout": false,
    "bod_reset_disabled": false,
    "wdt": "disabled"
}

For comparison, the config file of the Core Controller was:
{
    "boot_select": "aprom",
    "pwm_enabled_during_ocd": false,
    "ocd_enabled": true,
    "reset_pin_disabled": false,
    "locked": false,
    "ldrom_size": "0kb",
    "bod_disabled": false,
    "bod_voltage": "2v2",
    "iap_enabled_in_brownout": false,
    "bod_reset_disabled": false,
    "wdt": "disabled"
}

The relay board CPU programming command returned no error once:
# ./nuvoprog program -t n76e003 -a blink.ihx -c @config.json -v
2020/07/07 15:57:01 Performing reset {Auto Disconnect 0x00000001}
2020/07/07 15:57:01 >  0c10e2000000000000000400000001000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/07 15:57:01 <  0c04e20000005036ff00f8ffffff57012d0100002000fffffffffffff
fffffffffff000046662915699c03b4c74319896b6b8896664ef446d10e91c0d10a904c
2020/07/07 15:57:01 OK
2020/07/07 15:57:01 Performing reset {None (NuLink) Disconnect Ext Mode}
2020/07/07 15:57:01 >  0d10e2000000050000000400000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/07 15:57:01 <  0d04e20000005036ff00f8ffffff57012d0100002000fffffffffffff
fffffffffff000046662915699c03b4c74319896b6b8896664ef446d10e91c0d10a904c
2020/07/07 15:57:01 OK
 
But a read-back confirmed that the device ID has changed back to da3650:
# ./nuvoprog read -t n76e003  2relay_readback_bad.ihx
Error: Unsupported device
Usage:
  nuvoprog read [outfile.ihx] [flags]

Flags:
  -h, --help   help for read

Global Flags:
  -t, --target string   target device
  -v, --verbose         make verbose (enable debug logging)

Unsupported device

And the file is blank, so the 'program' action merely erased the existing relay program:

# head  2relay_readback_bad.ihx
:020000040003F7
:08000000FFFFFFFFFFFFFFFF00
:020000040000FA
:20000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:20004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:20006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:20008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
:2000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:2000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40

So now having unlocked the relay CPU for programming I now need to revert back to erincandescent's original code:

type DeviceID uint32
const (
        // N76E003, Observed in trace
        //
        // Matches IAP registers:
        //   0x00CCDDDD where
        //              CC   = Company ID
        //              DDDD = Device ID
        DeviceN76E003 = 0xDA3650
)
Whereupon the CPU behaves normally:
# /root/go/bin/nuvoprog program -t n76e003 -a blink.ihx -c @config.json
# /root/go/bin/nuvoprog read -t n76e003  2relay_readback_bad.ihx

            And the new blink.c program took:
# head  2relay_readback_bad.ihx
:020000040003F7
:08000000EFFFFFFFFFFFFFFF10
:020000040000FA
:200000000200060200997581071200E8E58260030200037900E94400601B7A009000EC78E8
:200020000175A000E493F2A308B8000205A0D9F4DAF275A0FFE478FFF6D8FD7800E84400C0
:20004000600A790175A000E4F309D8FC7800E84400600C7900900001E4F0A3D8FCD9FA02B9
:200060000003AC82AD83AEF0FF538EF774FC55894401F589D28CEC4D4E4F601A758ACB75AC
:200080008CFA108D0280FB1CBCFF091DBDFF051EBEFF011F80E0C28C2275B10075B2007575
:2000A000B30075B40075AC0075AD007E007F00C2959002BCE4F5F0C007C006120062D2954E
:2000C0009002BCE4F5F0120062D006D0070EBE00010FC3EE940AEF6480948040D29003E849

Now having wiped the firmware in a perfectly good WiFi Relay board, I need working N76E003 firmware. I need not have worried, for this being the Internet, cometh the hour, cometh the man, necromant. There is even a pre-compiled executable, firmware.hex!
 
I tried programming firmware.hex, but it did not work. And looking at the source code, src/main.c was the reason; the CPU pin assignments are different for the dual relay board. The code read:

#define RELAY4 P01
#define RELAY3 P04
#define RELAY2 P03
#define RELAY1 P05 #define RED P11
#define GREEN P00
#define BLUE P10 #define PWM_GREEN PWM3L
#define PWM_BLUE PWM2L
#define PWM_RED PWM1L #define BUTTON1 P15
#define BUTTON2 P12
And inside the main() loop are more hard code:
int main()
{
uart_init(19200);
printf("\n\n\nHello world. I'm a hacky opensource firmware for LC-tech modules\n");
printf("Go check out my blog https://ncrmnt.org for more awesome stuff\n");
/* Relays */
P01_PushPull_Mode;
P03_PushPull_Mode;
P04_PushPull_Mode;
P05_PushPull_Mode; /* LEDS */
P10_PushPull_Mode;
P11_PushPull_Mode;
P00_PushPull_Mode; /* Buttons */
P12_Input_Mode;
P15_Input_Mode;

By manually tracing out all 20 CPU pins using a multimeter, I corrected the code as:

#define RELAY4 P15
#define RELAY3 P12
#define RELAY2 P15
#define RELAY1 P12
#define RED P01
#define GREEN P04
#define BLUE P03
#define PWM_GREEN PWM3L
#define PWM_BLUE PWM2L
#define PWM_RED PWM1L
#define BUTTON1 P00
#define BUTTON2 P10
int main()
{
        uart_init(19200);
        printf("\n\n\nHello world. I'm a hacky opensource firmware for LC-tech modules\n");
        printf("Go check out my blog https://ncrmnt.org for more awesome stuff\n");
        /* Relays */
        P15_PushPull_Mode; /* Relay 4 */
        P15_PushPull_Mode; /* Relay 2 */
        P12_PushPull_Mode; /* Relay 3 */
        P12_PushPull_Mode; /* Relay 1 */
        /* LEDS */
        P03_PushPull_Mode; /* Blue */
        P01_PushPull_Mode; /* Red */
        P04_PushPull_Mode; /* Green */
        /* Buttons */
        P10_Input_Mode;
        P00_Input_Mode;
        /* buttonz */
        PWMPH = 0;
        PWMPL = 255;
        PWM_CLOCK_FSYS;
        PWM_CLOCK_DIV_128;
        PWM_EDGE_TYPE;
        PWM1_P11_OUTPUT_ENABLE;
        PWM2_P10_OUTPUT_ENABLE;
        PWM3_P00_OUTPUT_ENABLE;
        RED = 0;
        GREEN = 0;
        BLUE = 1;
        RELAY1 = 0;
        RELAY2 = 0;
        RELAY3 = 0;
        RELAY4 = 0;
To keep the changes to a minimum, I modified RELAY3 to be the same as RELAY1, and RELAY4 the same as RELAY2. Also the code defaulted to relays turned on at power-up, and I changed it to off.

Now not having the same IDE as nekromant, and not having the Makefile, I issued the build commands separately:

# sdcc -mmcs51  -c Delay.c -D FOSC_160000 -I../include
 # sdcc -mmcs51  -o 2relays.ihx main.c Delay.rel Common.rel -D FOSC_160000 -I../include
# sdcc -mmcs51  -o 2relays.ihx main.c Delay.rel Common.rel -D FOSC_160000 -I../include

And lastly the programming command:
# /root/go/bin/nuvoprog program -t n76e003 -a ./necromant/lctech-relay-altfw-master/src/2relays.ihx -c @config.json

And the LC Tech WiFi dual relay board worked, just like that. You can pick up the 2-relay version of nekromant's code from my github repository. Life is good.

Happy Trails. 

1 comment:

  1. HEllo Cmheong's can you please tell how to do this in windows

    ReplyDelete