LGT8F328P Arduino 'clones'

Arduino projects on the go
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

LGT8F328P Arduino 'clones'

Post by Martin »

Received my RF-NANOs today - the ones with the LGT8F328P chips, as recommended by Flynn. :)

I've not tried the RF part yet, if and when I get that working, I'll post it in the 'Frequency Hopping Experiments...' thread. But I didn't want to derail that thread with irrelevant stuff, so I thought I'd start this fresh thread about the non-nRF24L01+ aspects of the LGT8F328P chip.

Here's Ralph Bacon's excellent video about it. But don't use his method of setting up the Arduino IDE. See below for a more up-to-date method.



So, it's supposed to be 99% compatible with our normal Arduino chips used on the Nano, Uno, and similar, but with the following enhancements:
  • Cheaper!
  • Can run at 32 MHz (twice as fast as a regular Nano)
  • Works at any voltage from 1.8V up to 5.5V, at full speed.
  • Has analogue inputs that have four times the resolution (4096 steps instead of 1024).
  • Has additional built-in reference voltages (working range) for the analogue inputs: 1.024V, 2.048V, 4.096V
  • Has a real analogue output. Ordinary Arduinos can mimic analogue outputs by using PWM (rapidly switching on-off waveform).
  • Has six pins that can control a higher current (source or sink) than a regular Arduino - up to 80mA
  • Has a differential analogue input mode, for measuring the voltage difference between two pins
Getting it working.
Don't use the 'copy and paste the hardware folder' method explained in the Ralph Bacon video. Instead go to File->Preferences. Click on the little icon to the right of the Additional Boards Manager URLs: box and add this fresh line (after any that may already be present):

Code: Select all

https://raw.githubusercontent.com/nulllaborg/arduino_nulllab/master/package_nulllab_boards_index.json
Click OK

Then in Tools->Board>-Board Manger... search for Nulll and install the latest available verson of Nulllab AVR Compatible Boards. At the time of writing, my version was 2.0.0

Now, in Tools->Board->Nulllab AVR Compatible Boards, select Nulllab Nano/Maker-Nano, and select the Port in the usual way.

(Edit: I later found that it's better to select some different options: see the third post in this thread about analogue inputs. But it's fine to select Nano/Maker-Nano to get started.)

Now you can compile and upload programs in the usual way. Try the 'Blink example' :)

That's enough for my opening post. In my next one, I'll discuss testing the operating speed.
Last edited by Martin on 28 Jun 2022, 23:19, edited 1 time in total.
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

So, let's try toggling a pin on/off as fast as possible, and measure how fast it goes. We'll use Pin 13 (the one that 'Blink' uses).

Here's a first, naive, version - this is just 'Blink' but with the comments, and the delay(1000); instructions edited out.

Code: Select all

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  digitalWrite(LED_BUILTIN, LOW);
}
5_56.jpg
And that does a complete cycle (high and low) in 5.56 microseconds. Now we try adding the 'shift into high speed mode' described by Ralph in his video. This just means adding one #include and one call to set the clock_prescale in setup():

Code: Select all

#include <avr/power.h>

void setup() {
  clock_prescale_set(clock_div_1);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  digitalWrite(LED_BUILTIN, LOW);
}
Sure enough, now it runs twice as fast with each complete cycle taking 2.78 microseconds.

But Arduino programmers know that digitalWrite() is slow, and we can do better by writing directly to the PORT registers. Pin 13 is bit 5 of PORTB, so if we're not bothered about any other pins on the same port (Pins 8, 9, 10, 11, 12) we can just write 0x20 to PORTB to set pin 13 high, and 0x00 to set it low. Now we have:

Code: Select all

#include <avr/power.h>

void setup() {
  clock_prescale_set(clock_div_1);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  PORTB = 0x20;
  PORTB = 0x00;
}
192.jpg
Now it does a complete cycle in 192 nanoseconds (0.192 microseconds), that's over fourteen times faster, but the waveform is no longer symmetrical, with the 'low' part about five times as long as the high part. That's partly because of the overhead in the Arduino's loop() function - which we can eliminate by using an infinite while() loop inside setup.

Code: Select all

#include <avr/power.h>

void setup() {
  clock_prescale_set(clock_div_1);
  pinMode(LED_BUILTIN, OUTPUT);
  while (true) {
    PORTB = 0x20;
    PORTB = 0x00;    
  }
}

void loop() {
}
96.jpg
Now we're down to 96 nanoseconds, but there's still an asymmetry because the processor is basically doing three things:

set the pin high
set the pin low
jump back to the start of the loop

The jump instruction takes time to execute, and that means the low part of the output waveform is still twice as long as the high.

The Atmel Mega has a weird feature, where if you write a '1' to the PIN register when in output mode then it toggles the output to the opposite state. The PIN register is the one that you'd normally read when an I/O pin is in input mode. This is an unusual feature which most other microcontroller families don't share - if it works, it should even out the generated waveform, and because we're only writing to bit 5, the other pins of PORTB, if they were being used for anything, wouldn't be affected. It's also a good test of how compatible the LG chip is with the Atmel one.

Code: Select all

#include <avr/power.h>

void setup() {
  clock_prescale_set(clock_div_1);
  pinMode(LED_BUILTIN, OUTPUT);
  while (true) {
    PINB = 0x20;
  }
}

void loop() {
}
128.jpg
Sure enough it works. The waveform is even, and each complete cycle now takes slightly longer (128 nanoseconds) - which is to be expected because the microcontroller is now doing two pin change operations and two jumps for each complete cycle, rather than two pin change operations and a single jump.

At 32 MHz, each clock cycle of the microcontroller is just 31.25 nanoseconds, so it looks as though the compiler has optimized our code into just 2 cycles per loop - which would be impossible on an Atmel microcontroller (it takes 2 cycles to write to a port register and 2 cycles to jump). This LGT8F controller is not only running at twice the clock speed, it's also doing port writes and jumps in a single clock cycle! So for a simple program like this, it actually runs FOUR times faster than a regular Arduino chip could do! We can use some assembly code to perform the same function. We can use the processor's SBI (set bit in) instruction, and its rjmp (relative jump) instruction. sbi 0x03, 5 sets bit 5 (and only bit 5) of the register at address 3 (which is PINB).

Code: Select all

#include <avr/power.h>

void setup() {
  clock_prescale_set(clock_div_1);
  pinMode(LED_BUILTIN, OUTPUT);
  asm (
    "loop:         \n"
    "sbi 0x03, 5   \n" // write to bit 5 of PINB - this toggles the output 
    "rjmp loop     \n"
  );
}

void loop() {
}
That generates exactly the same output waveform, with a cycle time of 128 nanoseconds.

Conclusion: the chip is definitely running at 32MHz, also executes at least some operations in half as many clock cycles as an Atmel processor, and otherwise shows very good Atmel chip compatibility, so far.

My next post in this thread will be about the Analogue input resolution...
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

Let's try a simple program that reads the analogue input on pin A0, twice per second, and prints the values to the serial port. We can use the Arduino IDE Serial Monitor to view the output. This will also test the Serial routines, and the millis() function.

Code: Select all

void setup() {
  Serial.begin(115200);
}

void loop() {
  static uint32_t nextPrintMillis = 0UL;
  if (millis() > nextPrintMillis) {
    nextPrintMillis += 500; // print twice per second
    Serial.println(analogRead(A0));
  }
}
That works more-or-less okay. With the Serial Monitor set to 115200 baud, the output is legible and updates about every 500 ms. The values printed are in the range 0-1023, so it's only working at 10-bit (0 to 1023) resolution. But it's a tiny bit slower than two updates per second. I investigated by writing a sketch to just Serial.print(millis());

Code: Select all

void setup() {
  Serial.begin(115200);
}

void loop() {
  static uint32_t nextPrintMillis = 0UL;
  if (millis() > nextPrintMillis) {
    nextPrintMillis += 10000; // print every ten seconds
    Serial.println(millis());
  }
}
Here's the output, with the 'Show timestamp' option of the Arduino IDE Serial Monitor turned on.

Code: Select all

20:58:47.949 -> 1
20:58:58.192 -> 10001
20:59:08.469 -> 20001
20:59:18.713 -> 30001
20:59:28.959 -> 40001
20:59:39.203 -> 50001
20:59:49.447 -> 60001
20:59:59.692 -> 70001
21:00:09.970 -> 80001
21:00:20.213 -> 90001
21:00:30.456 -> 100001
21:00:40.701 -> 110001
21:00:50.947 -> 120001
21:01:01.191 -> 130001
21:01:11.470 -> 140001
21:01:21.716 -> 150001
21:01:31.960 -> 160001
21:01:42.204 -> 170001
21:01:52.449 -> 180001
You can see that the timestamps, which should be ten seconds apart, are a little more than that 180000 millis (three minutes) actually took three minutes, four-and-a-half seconds (21:01:52.449 - 20:58:47.949) so the chip's clock is running 4.5 / 180 * 100 = 2.5% slow.

The RF-NANO board has a crystal (16 MHz) which my sketch doesn't seem to be using. In the Arduino IDE Tools->Board->Nulllab AVR compatible boards section, you can choose different boards, but the only standard one that seems to work is the Nulllab Nano/Maker-Nano. If you choose DIY board, then it opens up other selections for Variant: (the RF-NANO has an LGT328P-LQFP32 package), CPU Frequency, and Clock Source: there are a multitude of options for the clock source. But if you set the clock source to anything other than Internal (32 MHz) or External (32 MHz) the code won't compile (you get the error "Clock Source Must 32MHz" [sic] If you set it to use External (32 MHz) then the code compiles and uploads, but doesn't run.

For now, I'll use "Nano/Maker-Nano" or "DIY Board" with Clock Source "Internal (32 MHz)", CPU Frequency "32 MHz", and Variant: LGT328P-LQFP32. Accept that the board may run a few percent slow or fast. I may figure out how to switch it over to using the crystal later.

What about setting the high-speed mode?

Code: Select all

#include <avr/power.h>

void setup() {
  clock_prescale_set(clock_div_1);
  Serial.begin(115200);
}

void loop() {
  static uint32_t nextPrintMillis = 0UL;
  if (millis() > nextPrintMillis) {
    nextPrintMillis += 10000; // print every ten seconds
    Serial.println(millis());
  }
}
Now, with the Nano/Maker-Nano option, millis() runs at double speed (so it prints every 5 seconds) and you have to set the Serial Monitor baud rate to twice the sketch selected speed to see the output. (Sketch:115200, Monitor:230400).
With the "DIY Board"; Clock Source "Internal (32 MHz)"; CPU Frequency "32 MHz"; Variant: LGT328P-LQFP32 things are better. The sketch prints every 10 seconds when in fast or slow mode, and the Serial Monitor always works at 115200. In fact, the clock_prescale_set(clock_div_1); doesn't do anything with this set-up: the board always runs in high speed regardless - I checked by running my speed test program with and without it.

So back to testing analogRead(), we find that adding the instruction analogReadResolution(12); to setup() does indeed switch the A/D converter up to using 12-bit accuracy.

Code: Select all

// no need for clock_prescale_set(clock_div_1); (makes no difference, and board always runs at fastest speed) if you use options
// "DIY Board"; Clock Source "Internal (32 MHz)"; CPU Frequency "32 MHz"; Variant: LGT328P-LQFP32

void setup() {
  Serial.begin(115200);
  analogReadResolution(12);
}

void loop() {
  static uint32_t nextPrintMillis = 0UL;
  if (millis() > nextPrintMillis) {
    nextPrintMillis += 500; // print twice per second
    Serial.println(analogRead(A0));
  }
}
Now, it prints values between 0 and 4095, and there doesn't seem to be much noise: when connected to a 1.5-volt battery it showed readings between 1399 and 1401, with a very occasional 1402 and no readings outside that range, over a period of several minutes.

Next, I'll try to check the Analogue output (the real one, not the PWM imitation).
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

Analog Output: as far as I've found so far, it only works at 8-bit resolution. Still, a cool thing to have!

Code: Select all

 // no need for clock_prescale_set(clock_div_1); (makes no difference, and board always runs at fastest speed) if you use options
// "DIY Board"; Clock Source "Internal (32 MHz)"; CPU Frequency "32 MHz"; Variant: LGT328P-LQFP32

void setup() {
  analogReference (DEFAULT); // 5v reference
  pinMode (4, ANALOG); // set pin 4 as analog output
}
 
void loop() {
  // write 8-bit values (0 to 255) to the DAL0 register to drive the output
  // first a nice high, square, trigger pulse for the scope to sync on
  DAL0 = 0;
  delay(1);
  DAL0 = 255; // give the scope a nice high pulse as a trigger
  delay(1);
  DAL0 = 0;
  delay(1);
  // now we can stick to values below 250, and carefully set the scope trigger to only work on the highest point!

  // ramp up
  for (uint8_t i = 0; i < 250; i++) {
    DAL0 = i;
    delay(1);
  }
  // ramp down
  for (uint8_t i = 249; i; i--) {
    DAL0 = i;
    delay(1);
  }
  // sine
  for (double a = 0.0; a < PI * 4.0; a += TWO_PI / 500.0) {
    DAL0 = 125.0 + sin(a) * 125.0;
    delay(1);
  }
}
analogOut.jpg
That's enough for today! I'll probably try some more things tomorrow: maybe even the nRF24L01+ part!
User avatar
Flynn
Posts: 64
Joined: 17 Feb 2018, 14:48

Re: LGT8F328P Arduino 'clones'

Post by Flynn »

The RF-NANO board has a crystal (16 MHz) which my sketch doesn't seem to be using. In the Arduino IDE Tools->Board->Nulllab AVR compatible boards section, you can choose different boards, but the only standard one that seems to work is the Nulllab Nano/Maker-Nano. If you choose DIY board, then it opens up other selections for Variant: (the RF-NANO has an LGT328P-LQFP32 package), CPU Frequency, and Clock Source: there are a multitude of options for the clock source. But if you set the clock source to anything other than Internal (32 MHz) or External (32 MHz) the code won't compile (you get the error "Clock Source Must 32MHz" [sic] If you set it to use External (32 MHz) then the code compiles and uploads, but doesn't run.
Excellent stuff Martin.... You are right... As far as selecting the external oscillator is concerned it seems that if you select 'Nulllab Nano/Maker' then it will employ the internal oscillator, however if you use these settings with 'DIY board' it is supposed to use the external osc...
ext_osc.jpg
There is also this little snippet..
Why is the HT42B534-1 USB to TTL module recommended for downloading the LGT8F328P module?
The built-in RC of the main HT has higher accuracy, and the 12M oscillator reaches 0.25%, so the download success rate is higher and the download is more stable under the same conditions!
If you use other built-in RC USB to TTL, please pay attention to it, if you frequently download unsuccessful, you can use this section to solve the problem!
Note: this model uses CH9340C serial chip,LGT8F328P external 16M crystal oscillator
Which seems to me to indicate 'they' recommend a separate USB-Serial adapter because 'the LGT8F328 internal USB-Serial is not reliable at 16MHz'!.. perhaps that was the reason you had problems with non-running code? Don't you just love Chinglish!
You only ever need two tools....WD40 and duct tape.
If it doesn't move when it should use the WD40 and if it moves and it shouldn't use the tape.
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

Thanks Flynn.

I'd not tried the combination of Clock Source: "External (16MHz)" and CPU Frequency: "16 MHz" (not sure why, as it makes sense). But I just tried it now.

With the (recommended) Upload Speed: "57600" it wouldn't upload - I get the error message:
avrdude: stk500_recv(): programmer is not responding
avrdude: stk500_getsync() attempt 1 of 10: not in sync: resp=0x5d
(all ten attempts fail)

I also tried the same Clock Source and CPU Frequency settings with Upload Speed: "115200" Then it compiles and uploads without error, but the program doesn't run (I tried a simple 'blink' program for that test, so as not to involve sketch baud rates and similar).

Tried the same combinations on two different RF-NANO boards. Same (failed) results on both. :(

So, at least until I can get a hardware programmer working (instead of the serial bootloader) I shall stick to these options:
DIYboardSettings.png
DIYboardSettings.png (11.24 KiB) Viewed 3360 times
Like that, the boards always run at 32MHz (albeit about 2.4% slow) without any need for the clock_prescale_set(clock_div_1);
millis() and the Serial baud rate then work correctly.

Edit: I decided to try to get a hardware programmer working next, and to that end I've swapped over to using this LGT8F328P Nano clone, which I've had for ages.
NonRFNano.jpg
It's a non-RF model, but with the same chip and no crystal. Interestingly, I had to change the Upload Speed to 57600 to get this one to work. Otherwise, the same settings of Internal 32 MHz, 32 MHz clock. This one has no crystal, but my speed test showed that this one runs 0.37% fast rather than 2.4% slow, like my RF-NANOs.

The reason I swapped is that this one has the programming pins SWD and SWC on the header at the end of the board. On the RF-NANO those pins aren't present. There are some non-through-hole pads on the bottom of the board, which I guess include the programming pins - I've not investigated those yet, but I will if and when I get the programmer working.
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »



That was somewhat of a struggle, mainly because the documentation is scattered all over the place and somewhat out of date. I think I'll document just what I did to get it working on my website, and then I'll post the details here too. I want to check the method I used works under Windows as well as Linux before I post it.

Here's a link to the blurb I posted about building an ISP programmer on my website. I won't reproduce all that stuff here: https://ceptimus.co.uk/index.php/2022/0 ... ogramming/
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

RF-Nano board has programming pads on the bottom, laid out in the form of a two-row, three pin header with 0.1-inch spacing, but they're not through-hole pads, so will be difficult to solder to. Also, my RF-NANO boards came with the two main rows of outside pins already soldered in place. This would normally be a good thing for plugging them into breadboards, but for converting them into RC receivers could be a nuisance - and it makes getting at the programming pins even harder.
LGT-RF-NANO_V2_0_bottom.jpg
I've belled them out and as far as I can see, they're in no industry-standard order. They're laid out like this

Code: Select all

GND  VCC  N/C
SWC  RST  SWD
The SWC pin is the square one, and SWD is at the other 'bottom' corner the way I've oriented the board in the photo. The other pins are also available on the board's regular pins, so the programmer only needs to make a temporary connection to those two. I think I can rig something up with some spring-loaded plungers to connect those two pads, and locate on some of the regular legs to get the other necessary connections and keep the spring-loaded ones located correctly.

I'm off out flying tomorrow, weather permitting, so probably won't make much more progress before the weekend. I intend to build a dedicated SWD programmer, and a rig for connecting and programming the RF-NANOs using that. Then I should be able to get the RF-NANO crystal working, so that the timing will be accurate when frequency hopping.
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

I built this handy-dandy compact ISP SWD programmer using one of the 'micro' LGT8F328-SSOP20-package boards mated to a CP2102 USB-to-serial adapter that happens to have the perfect pin arrangement to match the serial input side of the micro board. I had to swap the I/O allocation around a little, because the SSOP package chip doesn't have all the pins that the original sketch used. I'll post the modified sketch if anyone wants to build one. It works great for uploading sketches and burning bootloaders. I'll probably 3D-print a case for it, eventually.
ISPSWD1.jpg
ISPSWD2.jpg
Now I realize that the crystal on the LGT8F-RF-NANO belongs to the nRF24L01+ :lol: :roll: so there's no pressing need to use the ISP programmer on the LGT8F-RF-NANO anyway! I'll go back to serial-uploads for now, and investigate the nRF24L01+ part...
Martin
Posts: 744
Joined: 16 Feb 2018, 14:11
Location: Warwickshire

Re: LGT8F328P Arduino 'clones'

Post by Martin »

First check I like to do, (after the isplus.ino sketch to prove that the MCU can talk to the nRF24L01+ chip) is to transmit a (vanishingly weak) carrier wave, and see if that appears on the band scanner. So far, so good!

Attachments
nRF24L01pTransmitCW.zip
(2.32 KiB) Downloaded 73 times
Post Reply