Sunday 19 July 2020

AS3935: The Next Generation Episode 2

Hors de combat: AMS1117-3.3 LDO with crater and ejecta

In Episode 1, I isolated the modem ADSL disconnect relay module, and this setup survived about three months of storms, until this week. The system worked pretty well: the remote AS3935 disconnected the ADSL line from the modem a good 20 minutes earlier, so the problem area was limited to just the relay board. Instead of blowing everything up like my first rig.


Setup at time of strikes


Relay board with ESP-01S dismounted. No obvious burn marks this time.

However the ADSL line is still connected to the relay board pins, a lightning strike first took out the 12V to 5V DC-DC buck converter that served as the power module for the relay board. This caused the output to short-circuit to the input: 12V from the battery now appeared at the relay board power input.

Relay board after the second strike. Note the insulation tape over the relay pins

Now the AMS1117-3.3 LDO power regulator in the relay board is rated for 15V and while it crashed the ESP8266 CPU it probably  did not kill it. It did cause the 5V relays to run really hot. This set it up for the second close strike, just minutes later, which blew a neat little hole in the AMS1117-3.3.

It is very impressive what damage lightning can do. But there seems to be progress. The AS3935 lightning detector allowed an early modem disconnect, which probably saved the modem. And this time round there seems to be a lot less damage, probably because the lightning could not find an easy path to earth. The earlier 'disconnect' signal from the AS3935 module caused a second relay board to disconnect the battery charger from the mains. At the time of the second strike the system had been running off the 12V battery.

Since the strike also killed the 12V-5V DC buck converter powering the relay board from the battery, perhaps disconnecting the ADSL relay board from the buck connector might improve things. It does not really need to be powered up: I can use the relay 'Normally Open' pins to ensure the ADSL stayed disconnected. The relay board's 5V is really close to the ADSL pins as it needed to power the relay coil.

And I can make things a little more robust by using a 12V relay board to disconnect the ADSL relay board and to monitor for the storm's passing so that the modem can be reconnected when it is safe.

Diymore 4-channel WiFi Relay board with serial interface
And as a bonus the module PCB designer has helpfully cut a slot around the vulnerable relay output COMMON pin.

Note the 'U'-shaped slots cut around the relay COMMON pin

The power regulator is still an AMS1117-3.3 but now there is an added 78M05 linear regulator in series. This raises the maximum input voltage (ie the tolerance to surges) to 35V, from the AMS1117-3.5's 15V. Hopefully this is enough, but we are never really sure until the next lightning strike demolishes it. The relay coils are still exposed to the full weight of the surges but they are relatively tougher devices.

The setup is now thus:

System block diagram: the other 2 relays in the 4-channel module are used to disconnect the battery charger from the mains

Next Generation Episode 2 build: from top: 2-channel ADSL relay module, ADSL modem and 4-channel power disconnect module

Thus fortified, we await the next thunderstorm. Indeed I welcome the strikes, for it is looking like my 30-year struggle with lightning strikes may be coming to a close: fiber-optic broadband network has reached my front gate, and the service provider salesman will not be long after. Just when I felt like I am winning.

Fiber at the gates: the end for copper-based ADSL broadband is nigh


What is Ahab without his Moby Dick? Come, lightning and welcome. 


Happy Trails.

Ahab and his whale



Thursday 9 July 2020

Using yet another CH340 USB dongle as ESP-01S Programmer


You Can't Always Get What You Want

In my previous post I modified a CH340 USB to ESP8266 adapter. It worked well, but after programming an ESP-01S I kept having to re-plug it into the USB port in order to test it. Wouldn't it be nice if I could buy one with a built-in reset switch?


Diymore CH340G USB to ESP8266 ESP-01S Adapter



The DIYMore CH340G USB to ESP8266 Adapter looked like just the ticket. There's that built-in switch. and I know the CH340 worked well with my Arduino installation. And at RM5.24 it was even cheaper than the old model.

I guess if things looked too good to be true on the Internet, sometimes it is. It did not work. While it implemented the CH_PD to GPIO 0 switch, it did not pull GPIO 2 and CH_PD high, so the ESP-01S does not start up, and will neither run nor accept a program. 

ESP-01S Pinout


The cure is the same as that for the WiFi ESP8266 ESP-01S Relay module: short CH_PD to VCC and connect a 10K resistor between GPIO 2 and VCC. The modified Diymore CH340 USB to ESP8266 Adapter now looks like this:

Short CH_PD to VCC and connect a 10K resistor from GPIO 0 to VCC

Now it works. To program, you flip the switch to 'PROG' and plug the dongle in. You then flip it back to 'UART' and flash your Arduino IDE sketch. To run, you plug it in with the switch at 'UART'.

Except I still have to unplug and plug it in to test my new programs. I guess you can't always get what you want.  But if you try, sometimes you'll find you get what you need.

Happy Trails. 


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. 

Tuesday 7 July 2020

Flashed Before My Eyes: Nuvoton N76E003 CPU Part 1 of 2


Nuvoton N76E003AT20 Core Controller Board

Nowadays the CPUs I use most often are Raspberry Pi, ESP8266 and Arduino. And a couple of ancient Intel-based laptops and of course my ARM-based smartphone. I have desktop PCs which I have not turned on in years.

Software is key:  just because it is more convenient (and just as cheap) to solve a problem using Raspbian or Arduino IDE, I still have stocks of 6502, 8752AH, PIC16F84 and PIC18F14K50 which I have not used in decades. So why bother setting up yet another CPU development system?

At RM6.2 (USD1.50) the Nuvoton N76E003AT20 Core Controller Board compares unfavorably with the Arduino Nano 'compatible' or even the ESP-01S. Just because the last two is supported by the Arduino IDE and it vast library. The N76E003 is usually programmed in C, usually via a proprietary IDE like Keil or IAR.

But it has one thing going for it: it is used in my favorite ESP-01S Relay Board, LC Technology's 5V WiFi Relay.

LC Technology WiFi dual Relay Board

Often pirated and sold as "2-Channel WiFi Relay" at RM19(USD4.50) including the ESP-01S CPU, it has been a mainstay of many IoT projects. Unlike some even cheaper WiFi relay boards, this one uses a serial TTL interface and has its own CPU, the Nuvoton N76E003.

There are two push-buttons for input and 3 LEDs, which can be PWM-ed. The onboard AMS1117-3.3 LDO gives it a good input power range, from 15V to 5V. And it still has spare, usable CPU pins. Together with its relays and WiFi capability, this makes for a very capable IoT design. Here's my hack (based on Zaschipas) on the 1 relay version of this board.

Indeed the same basic design is used in very many cheap China IoT devices (smart light bulbs, power switches, etc), usually supported by the eWeLink App. The IoT and WiFi portion has already been open-sourced via Tasmota and others, but if you can re-program the N76E003, you can extend or re-purpose it. And even better if you can use open-source programmers and IDE.

Since this is probably a low-use system I aimed for a cheap CPU programmer, something sold as "Nu-Link Simulator Offline Download Function Full Series of N76E003" for RM58. 

Nu-Link Simulator Offline Download Function Full Series of N76E003


This is probably derived from Nuvoton's Nu-Link-Me programmer so the schematics are not likely to be very different.

Nuvoton Nu-Link-Me

The usual software for Nuvoton Nu-Link-Me is the proprietary Keil or IAR. There is a delicious  NuEclipse for Linux but sadly it is for their ARM-based NuMicro series. You can probably run Keil with Wine in Line, but I decided to try erincandescent's nuvoprog.

nuvoprog runs on Go. I used a Debian system as nuvoprog had problems installing on my Slackware machine.  There's the usual Debian preamble:

# apt-get update
# apt-get upgrade

Next I downloaded Go, and installed it:
# tar -C /usr/local -xzf go1.14.4.linux-amd64.tar.gz

# vi /etc/profile

Added /usr/local/go/bin to PATH

# export PATH=$PATH:/usr/local/go/bin

A quick test is in order:

# cat hello.go
package main
import "fmt"
func main() {
  fmt.Printf("hello, world\n")
}

# go build hello.go
# ./hello
hello, world

Now for nuvoprog:
# go get -u github.com/erincandescent/nuvoprog
go: missing Git command. See https://golang.org/s/gogetcmd
package github.com/erincandescent/nuvoprog: exec: "git": executable file not found in $PATH

OK, I need git.

# apt-get install git
root@aspire5050:/home/heong/go# go get -u github.com/erincandescent/nuvoprog
# github.com/karalabe/hid
exec: "gcc": executable file not found in $PATH

And gcc.

#  apt install build-essential

# gcc --version
gcc (Debian 8.3.0-6) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

# apt-get install manpages-dev

Now it works:
# go get -u github.com/erincandescent/nuvoprog

Rather inconveniently it was installed in /root:
# ls -l /root/go/bin
total 5184
-rwxr-xr-x 1 root root 5306096 Jul  6 17:22 nuvoprog

I plugged in the Nu-Link programmer and got:
#/root/go/bin/nuvoprog read -t n76e003 dev.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

At least it recognized the programmer. Time to plug in the N76E003 Core Controller board. A little hiccup here: the Nu-Link programmer (and cable) is dual row by 5 way and the Core Controller board is a single row 8-pin header.

Note the programming port on the left and unpopulated J2


A quick check of the pinouts showed that the Nu-Link only used one of its 2 rows. The Core Controller programming port pinouts show that the first 5 pins are compatible with the Nu-Link pinout. So if I soldered a 5-way header into the Core Controller this would fit the Nu-Link cable.

If you orientate the cable connector via its polarizing tab when plugged in correctly overhangs the edge Core Controller.

Check that your Nu-Link voltage is set to 3V3, and just like that, it works:
#/root/go/bin/nuvoprog read -t n76e003 dev.ihx
# ls -l
total 122896
drwxr-xr-x 2 root  root       4096 Jul  6 17:29 bin
-rw-r--r-- 1 root  root      29256 Jul  6 17:48 dev.ihx
-rw-r--r-- 1 heong heong 123711003 Jul  6 17:05 go1.14.4.linux-amd64.tar.gz
-rwxr-xr-x 1 root  root    2080884 Jul  6 17:10 hello
-rw-r--r-- 1 root  root         74 Jul  6 17:10 hello.go
drwxr-xr-x 3 root  root       4096 Jul  6 17:29 src

The resulting file dev.ihx is blank, but then so is my Core Controller board.
# cat dev.ihx | head
:020000040003F7
:08000000FFFFFFFFFFFFFFFF00
:020000040000FA
:20000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:20004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:20006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:20008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
:2000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:2000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40

For a compiler, I used the tried and true sdcc:

# apt-get install sdcc

Next we want a simple 'Hello, world" toy program for the N76E003 Core Controller. I did not need to look far, for erincandescent has blink_raw.c. Unlike many other sample programs, it only needed one include file, n76e003.h. I downloaded both files to the same directory and simply modified the path to the include file. Also note corrected output pin P15:

# cat blink.c
/* Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */
#include <stdint.h>
#include "n76e003.h"
// 16Mhz clock
#define CLOCK 16000000L
// Divide by 12
#define T0CLOCK ((CLOCK)/12L)
// Per milisecond
#define T0_1MS ((T0CLOCK)/1000L)
static void msdelay(uint32_t count)
{
        uint16_t reload = -T0_1MS;
        // Input = Fsys/12
        SET_FIELD(CKCON, T0M, 0);
        // Mode 1
        SET_FIELD(TMOD,  T0M, 1);
        // Start
        TR0 = 1;
    while (count != 0)
    {
        TL0 = reload      & 0xFF;
        TH0 = reload >> 8 & 0xFF;;
        while(!TF0);
        TF0 = 0;
            count--;
    }
    TR0 = 0;
}
void main() {
        // Set pins in old-skool Quasi Bidirectional mode
        P0M1 = 0;
        P0M2 = 0;
        P1M1 = 0;
        P1M2 = 0;
        P3M1 = 0;
        P3M2 = 0;
        for (;;) {
                int i;
                for (i = 0; i < 10; i++) {
                        P15 = 0;
                        msdelay(1000);
                        P15 = 1;
                        msdelay(1000);
                }
                msdelay(2000);
        }
}
You should also download the config.json file:
# cat ./config.json
{
    "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"
}

It compiles nicely (ignore the warning):

# sdcc blink.c -D FOSC_160000
blink.c:24: warning 158: overflow in implicit constant conversion

# ls -l
total 224
-rw-r--r-- 1 root root 13593 Jul  6 18:40 blink.asm
-rw-r--r-- 1 root root  1428 Jul  6 18:31 blink.c
-rw-r--r-- 1 root root   664 Jul  6 18:40 blink.ihx
-rw-r--r-- 1 root root   242 Jul  6 18:40 blink.lk
-rw-r--r-- 1 root root 42153 Jul  6 18:40 blink.lst
-rw-r--r-- 1 root root 26106 Jul  6 18:40 blink.map
-rw-r--r-- 1 root root  1163 Jul  6 18:40 blink.mem
-rw-r--r-- 1 root root  6756 Jul  6 18:40 blink.rel
-rw-r--r-- 1 root root 42153 Jul  6 18:40 blink.rst
-rw-r--r-- 1 root root 49393 Jul  6 18:40 blink.sym
drwxr-xr-x 2 root root  4096 Jul  6 18:30 include
-rw-r--r-- 1 root root  8337 Jul  6 18:40 n76e003.h

And programs just as nicely with:

# /root/go/bin/nuvoprog program -t n76e003 -c @./config.json -a ./blink.ihx

But there is a problem: the LED did not blink. Luckily mark-fink mentioned that a Core Controller board just like mine had an unpopulated jumper J2 that needed soldering. And, the pin controlling the LED is P15 instead of P12.

Add a jumper (in green) to the Core Controller board for blink_raw.c to work


After a recompile and reprogram the Core Controller blinked nicely. OK so I have a working N76E003AT20 development system. 

Now for the LC Technology Dual Relay WiFi board. The header pinouts were almost identical, except CLK and DAT were reversed. Naughty of them, but never mind: it is just an inconvenience. Another cable should do the trick.
            
            Nu-Link                  2-channel relay
            3V3
            DAT                            CLK
            CLK                            DAT
            RST                            RST
            GND                            GND

Nu-Link programmer wired to Relay Board. Remember to remove the ESP-01S from its socket while programming


The relay board is a 5V device. If you popped the Nu-Link case open, there is a jumper to set the Nu-Link voltage to 5V. Be careful to set it back to 3V3 when using it for the Core Controller though, which takes 3V3 at the programming port.

If we now try to read the N76E003 progran from the relay board it fails:

# /root/go/bin/nuvoprog read -v -t n76e003  ../nuvoton/2channel_relay_readback.ihx
2020/07/06 20:25:22 >  013efffffffffffffffffffffffffffffffffffffffffffffffffffff
fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
2020/07/06 20:25:22 <  0114fd1a00000920010068882f615a01320100002000000064c2a6e91
28d78a54955484b46e6291d69bc03b6c70319896b2b8892674ef446d10e15c0d12a907c
2020/07/06 20:25:22 Setting config {1000 N76E003 3300 0 0}
2020/07/06 20:25:22 >  0218a2000000e803000000080000e40c0000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/06 20:25:22 <  020ca20000000920010068882f615a01320100002000000064c2a6e91
28d78a54955484b46e6291d69bc03b6c70319896b2b8892674ef446d10e15c0d12a907c
2020/07/06 20:25:22 OK
2020/07/06 20:25:22 Performing reset {Auto ICP Mode Ext Mode}
2020/07/06 20:25:22 >  0310e2000000000000000500000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/06 20:25:22 <  0304e20000000920010068882f615a01320100002000000064c2a6e91
28d78a54955484b46e6291d69bc03b6c70319896b2b8892674ef446d10e15c0d12a907c
2020/07/06 20:25:22 OK
2020/07/06 20:25:22 Performing reset {None (NuLink) ICP Mode Ext Mode}
2020/07/06 20:25:22 >  0410e2000000050000000500000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/06 20:25:22 <  0404e20000000920010068882f615a01320100002000000064c2a6e91
28d78a54955484b46e6291d69bc03b6c70319896b2b8892674ef446d10e15c0d12a907c
2020/07/06 20:25:22 OK
2020/07/06 20:25:22 Checking device ID
2020/07/06 20:25:22 >  0508a3000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000000000
2020/07/06 20:25:22 <  0508a30000005036ff0068882f615a01320100002000000064c2a6e91
28d78a54955484b46e6291d69bc03b6c70319896b2b8892674ef446d10e15c0d12a907c
2020/07/06 20:25:22 OK, Device ID  0x00ff3650
Error: Unsupported device
Usage:
  nuvoprog read [outfile.ihx] [flags]

Flags:
  -h, --help   help for read

Now it does look like the N76E003 is responding, except now the CPU Device ID 0x00ff3650 is not recognized. This will be addressed in Part 2.

So, we have a Linux development system for the N76E003 and showed it to work for the N76E003 Core Controller board, but not for the LC Technology Relay board. 

Happy Trails

Thursday 2 July 2020

Raspberry Pi 4 Voice Assistant Part 2 of 4: Google Text to Speech




gTTS: The Empire Strikes Back


In Part 1, one of my goals was to have my laptop issue voice commands to to my Google Home smart speaker. After trying out Mycroft, Jasper seems like the logical next step. The other text to speech systems voice quality were something like the Texas Instruments Speak & Spell products: especially ESP32Talkie. Even Mycroft sounded a bit sad next to my Home Mini speaker.

And then I stumbled upon gTTS, Google Text to Speech.  This python interface to Google's text to speech can be installed using:

pip install gTTS

And requires a program, of only ten lines:

from gtts import gTTS

def text_to_speech(input_name, output_name, language):
    file = open(input_name, 'r')
    content = file.read()
    file.close()
    sound = gTTS(text=content, lang=language)
    sound.save(output_name + '.mp3')
    #https://pypi.org/project/gTTS/
text_to_speech('input_en.txt', 'sound_en', 'en')
#text_to_speech('input_tr.txt', 'sound_tr', 'tr')
print('Done!')

You put your text in a file, input_en.txt:
$cat ./input_en.txt
Hey, Google

$python tts.py

And you get back an mp3 file, sound_en.mp3

And all you need to do now to trigger the Google Home smart speaker is:

$mplayer sound_en.mp3

A typical complete command would be something like:
$mplayer HeyGoogle.mp3; sleep 1; mplayer OfficeLampOn.mp3

For some reason, the other trigger phrase 'OK Google' did not work, but for very little effort I can now integrate disparate IoT devices, be they home brewed, Alexa, or Google Home into one Voice Assistant that rules them all.

Here's what it sounds like:



Happy Trails.

Luke: Vader... Is the dark side stronger?

Yoda: No, no, no. Quicker, easier, more seductive.