Thanks to visit codestin.com
Credit goes to blog.tynemouthsoftware.co.uk

Showing posts with label Microcontroller. Show all posts
Showing posts with label Microcontroller. Show all posts

Sunday, 21 December 2025

Faster isn't always better - A cautionary tale

I have a project on the bench that has been dragging on for a while, and I just want to get it finished.

I can see it being finished in one of two ways.

1) I get it working, and working well and get it into production

2) I conclude to my satisfaction that it's not going to work so I can move on to something else

It is one of those projects that is always going to be doomed to failure if you are not careful -  trying to do something in software which would be better done in hardware.

And yes, the answer is easy, just do it in hardware. 

Well, as usual, there are various problems with that. Modern microcontrollers can do an awful lot and can be of great benefit in terms of cost and board space and simplifying things.

And also the hardware is not necessarily available, some of it went out of production in the early 1980s, some of it only recently, but it doesn't seem like any of it is likely to come back

Until they make a 3D printer which can produce custom silicon chips, it's a software solution.

(I am sure that will happen sometime in the next 5 years, people are already making their own silicon. That is assuming we don't end up in some kind of technological dark age where knowledge is feared and banned by the powers that be ....)

What I need to do

I need a microcontroller to do some fast IO. I need it to detect a signal, read some data and respond to it within a short window.

My microcontroller of choice here is the AVR128DA48 or one of that series. These run at 24 MHz and has mostly single cycle instructions, specifically including single cycle access to the IO ports.

That means I should be able to run up to 24 million instructions per second.

In this application, I am waiting for a pulse from a 1MHz system, and so being 24 times faster, I should have 24 instructions to do it?

Well, not quite.

The pulse is actually only active when the clock is high, only half a cycle, but that's fine, that is still 12 instructions.

I got my code down to 10 instruction cycles and tried it.

It worked most of the time.

Not good enough.

Checking deeper, it turns out I don't have 12 cycles, the pulse is asymmetric, so I only get about 8-10.

The first instructions are along the lines of "is the pin low, no? loop back and test again" which takes up to three of the cycles, depending which cycle the tested pulse falls on, so in some cases, it just misses the change and takes the full 10 cycles, and is a bit late.

Here I am monitoring an LED signal I am using for testing. It is activated last, so if that still falls within the pulse, it should be safe.

But if it comes too late, it is likely the preceding pulse will also have been missed.

I have tried various things to streamline the code, but I think it is about as optimal as it can be.

There are various elements to this:

  1. detect the pulse
  2. work out the response
  3. respond
  4. clear and loop back for the next one.

I think I can save a few cycles on steps 3 and 4 by using some additional hardware, and maybe optimise the processing, but that only gets me close to the 8 cycles I have.

I can't work out the response in advance as it will be different every time.

I would prefer to have a lot more clear space than that. 24 cycles to run 10 instructions would have been reasonable, 8 cycles to run 8 instructions is too tight, specially given likely variation in the host hardware, some machines may be 7, some may be 9 etc.

What about interrupts?

Just as a side note, could I save time on the detection using an interrupt?

Well, no.

It looks like it is going to be about 6 cycles before it even gets to my code, so that's not an option.

An Alternative Option

I put that to the side for a while and got on with some other things, including building a Minstrel ZXpand that had been ordered.

Whilst programming the microcontroller for that, I wonder if the PIC18F4525 used on the ZXpand might be better, that has a couple of features that might help?

I covered my early adventures with PIC microcontrollers in a previous post, I glossed over the point I switched my allegiance from Microchip to Atmel.

(get ready to mark off the first "bloated framework" on your Dave rants Bingo card, possibly the first of many)

I had been working on a project and was getting frustrated by the PIC development environment, generating too much code, and code which didn't build or didn't work.

Whilst I had put that to one side, this thing called an Arduino started to appear, and that used the Atmel ATmega328, and I started looking into that and was impressed.

Since then I have been sticking with the Atmel family (which was going great until Microchip bought them out, but that's a rant for another day).

PIC a number

I wonder what's been going on with the PICs, maybe there is something in the PIC world that would help?

The chip in the ZXpand only works up to 20MHz, oh well, maybe not.

But then I noticed some other chips which said they would run up to 64MHz.

Now you're talking, 64MHz internal oscillator, that would mean I have 32 instructions for the half cycle, with the asymmetry, maybe 24, and my code is 10, so that would be a a good clearance.

We're back in business.

Oh great, there are dozens of part numbers and no clear indication of what the differences are.

I mean who put the marketing department in charge of a technical website. Who is that sort of table aimed at? it's just nonsense. Can Microchip please find someone with a grey beard and let them write a useful version of that.

OK, it's getting late in the day, but if I order a few of these now I will get them in the morning. So I scatter bought a selection of the Curiosity Nano boards, which are development boards with integrated programmers, which means I don't need to bother messing about with PICKits or Snaps etc.

Testing Methodology

You get an ology and you're a scientist.

The most important thing here is the IO operations, so to test things, I wrote a little bit of code which toggles an IO pin as fast as it can.

Loops can throw things out, so I have been doing eight instructions that turn the output pin on and then off alternately.

I have written versions in assembler with a register holding the value to write, but here the compiler optimised that to some single cycle instructions, so I am happy enough to stick with C for now.

I am not concerned about the overhead at the start or the loop, as I can just measure the speed of the 4 pulses. It gives 4 pulses at top speed, then a gap, then another 4.

Out of the box, the AVRxDx chips run at 4MHz, so when I run the code, it turns the output on and then off 4 times in 8 cycles, so I see a run of pulses at 2MHz.

With a bit of extra code to change the clock, it can get 24MHz.

The clock settings are locked, so you need to set a register to enable access for a few cycles, so that bit has to be in assembler.

(you also need to set RAMPZ if using the 128K chip, but I am just testing here)

Now I get a train of pulses at 12MHz, which is as fast as I can change them with a 24MHz clock.

If these new chips run at 64MHz, that should mean similar test code would generate a stream of pulses at 32MHz.

Now I just need to wait for the postman......

Lots of red boxes, I tried to cover all the eventualities.

These are all Curiosity Nano boards, quite neat development boards with a built in programmer debugger and pins for all the signals, and available with lots of different microcontrollers on them.

The PIC18F57Q43 seemed to do everything I would need.

I will spare you all the faffing around with different system like Atmel Start and Microchip MCC, Microchip Studio and MPLAB X, automatically generated code and hand turned from a blank page. Suffice to say I tried every combination I could think of, and the best I could get was 8MHz.

I was using the simplest code with the same sort of loop as before.

Checking the listing file, it is indeed using the BCF and BSF instructions that I would like to use.

And double checking, those instructions are 1 cycle instructions, highlighted below.

It is supposed to be running at 64MHz, but the pulses are only showing up at 8MHz, which if they are "single cycle", as it appears from the listing file they are, then the chip is running at only 16MHz?

Looking around it finally dawned on me, on the PIC, clock cycles and instruction cycles are not the same.

They really should have had that in big flashing lights at the start.

Each instruction cycle is actually 4 clock cycles, so 64MHz is 16MIPS.

On the AVR they are the same, 1 instruction cycle is 1 clock cycle, so 24MHz is 24MIPS.

That means these PICs are slower than the AVR.

Well, that was a bit of a waste of time.

I had started thinking about a couple of projects I could revisit with the extra speed, and the better peripherals the PIC chips have over the AVR, but sadly they just aren't going to be fast enough.

They might come in handy one day on something that doesn't need as much speed, but for this application they aren't going to help.

But wait, what's this other red box I bought?

I don't really want to move to an ARM chip, I would like to stay 8-bit if I can, but there are some ATSAMC microcontrollers which might do the job. These run at 48MHz (it says there is a 64MHz option, but that seems to be a different part number with a -64 on the end), but either way, that's got to be better than 24MHz or 16MHz.......

As part of the scatter buying exercise, I had picked up the ATSAMD21 Curiosity Nano. That's not ideal, I would prefer the ATSAMC21 as that is 5V, and the ATSAMD21 is 3.3V, but I thought I could at least get a proof of principle test working and look at other options later.

Credit here for this very useful table in the datasheet which explains the major differences between versions.

Why can't they do that for the other series of chips?

This is what they show for the AVR series. Same nonsense as for the PICs.

More expletives and trying different development environments and toolchains etc. Endless updates and completely reinstalling one of the development studios which broke itself doing even more updates.

5.86MHz is the best I could get out of it. How did it even get there? That isn't an integer multiple?

I think that is running at 48MHz, but it is using internal PLLs generated from 32.768KHz, and I am not quite sure I got the configuration right. How did it get down to 5.88MHz? Confused.

It does have an 8MHz fixed oscillator. I know it's not using that as the best I could hope to get from that would be 4MHz toggling if it were one clock cycle per instruction (which I doubt it is).

I remembered I had looked at the ATSAMC series before, I couldn't find any of the boards I had, but I did find a sole IC.

(how I found one single IC in my house is quite a miracle, finding the PCBs as well would be too much to ask).

The ATSAMC series have two advantages over the ATSAMD as far as I can see. They run at 5V, and they have an internal 48MHz oscillator as well as the 8MHz one. Maybe I had the configuration of the PLL wrong? With a fixed 48MHz oscillation there should be no problem getting full speed.

Can I just swap the ATSAMD on the Curiosity Nano board?

Is that chip smaller or further away?

Ah no then. Although both are available in 48 pin and 64 pin versions (and many other variations), the board is 48 pin and the chip is 64 pin. Of course they are different. I wouldn't be that lucky.

OK, time to see if the jungle website can rush me a breakout board I can use for a 64 pin 0.5mm TQFP.

Anyway, at 1AM I ordered an overpriced breakout board from Mr Bezos, which he promised to bring to my door in the morning.

(how is that "compatible with Arduino", in what conceivable way would you use that with an Arduino? Oh never mind. )

Seems to fit, it's the right pitch, even if the pin numbering and pad ordering is completely wrong as the board is designed for TQFP 100.

Add sockets for all 64 pins and a few decoupling capacitors (and the obligatory power LED).

I just need a programmer.

Luckily, the Curiosity Nano boards can do that, if you cut some of the traces on the back to disconnect the onboard programmer from the original microcontroller..

Not the neatest, but it should work. (It's JTAG, so more wires than the PIC or AVR)

Again, lots of messing around with code generation and bloated frameworks etc.

I also had to reconfigure the Curiosity Nano onboard programmer to suit the different part. I haven't needed to do that on the AVR versions, I built a programmer using a Curiosity Nano that I have used for a variety of parts.

The ATSAM one wasn't having any of it, so I had to change it. I found pyedebuggerconfig which allowed me to to change the target chip type (and host device voltage limit) and I was away, it was talking to the chip.

Great.

Now for the code.

Well, that's helpful. Thank you Atmel Start.

I managed to get some code built in MPLab X, that also required a bit of fiddling to get it to switch to the 48MHz oscillator, but I got there, and here is the fastest I managed to get it to twiddle IO pins.....

8MHz.

Bugger.

I don't know much about ARM assembly, but the compiler got it down to a single instruction for each bit toggle.

I can only assume that instruction takes six clock cycles, and I couldn't find any obvious alternatives that would be faster.

So after all that, it is also slower than the chip I started with.

(even the 64MHz model would end up 10 and a bit MHz, still slower than the AVRs)

Any other options?

I have previously looked at some different ARM chips, including the STM32F405. Those run at 168MHz, so should be fast enough. However, that is a whole new framework and toolchain to learn from a different manufacturer and probably a step too far.

Conclusion

None of these chips are fast enough to do what I need to do in the time available.

A frustrating, but necessary exercise, due diligence.

This project, in this form, is not viable with the parts I have looked at.

I think I have to give up on this project.

Unless something changes or a new part comes along that will do the job (or I find there is one that I have somehow overlooked).

But, on the positive side, I can clear my bench and start on something new in the morning.

Post Script

Whilst putting this post together, I had a look for photos of the board I first tried the SAMC20 with.

I also found I had edited some of the photos, so I must have written a blog post about it, but this was in the dark ages of 2021 when the public blog was offline and I was writing only for Patreon.

Thank you to the Patrons that stayed with me through that and kept me (just about) sane.

I think this was the main photo for that article - I don't think it went very well.

In that post, I ended with a photo of a note I left myself.

If only 

1) I had remembered that 

or 

2) I had found the box.

Oh well.

Those who do not learn from history are doomed to repeat it.....

Post-Post Script

Since posting this on Patreon last month, I have managed to get the project working, not the ideal version I was hoping for, but still quite nice. It's a bit messy, hopefully the production version will be a bit neater. (ignore the board, that was just an old board used as a base to hold it all together.)


Adverts

My Tindie store is still open, the Christmas deadline is passed for everywhere other than the UK (if you are very quick).

Although that doesn't seem to be a problem the way things have been recently.


Patreon

You can support me via Patreon, and get access to advance previews of development logs on new projects like the Mini PET II and Mini VIC and other behind the scenes updates. This also includes access to my Patreon only Discord server for even more regular updates.

Sunday, 14 September 2025

New Microcontroller Features Part 1

I first used microcontrollers in the early 1990s, with I think the PIC16C54, a homemade parallel port programmer and one of the versions of this book constantly on my desk.

Looking at the features of that now it rather surprisingly minimal.

  • It has one 8 bit timer.
  • 512 bytes of code and 25 bytes of RAM.
  • That's it.

No 16 bit timers, no UART, SPI, I2C, Analogue functions, SRAM, touch sensors, USB, LCD drivers etc.

The technology of those microcontrollers goes back to the 1980s. There was a earlier version of that chip in the ZX Spectrum+ external keypad (back before Microchip split from GI).

Those were meant to be developed with ceramic EPROM versions with glass windows to UV erase the contents. The production chips were one time program.

It feels like the stories you hear of people writing programs on punched cards and then getting one shot to run them on the actual mainframe, and it may or may not have worked.

I had one shot. I bought the chip, wrote the code, programmed it and hoped it would work.

If it didn't, I had to raid my pocket money and buy another chip. I think I finally got some LEDs flashing on the second or third attempt, but I was very proud at the time.

PIC16C84

A few years later the PIC16C84 came along with double the program memory, and it was now EEPROM program memory which was electrically erasable, and so could be programmed time and time again.

My first PIC16C84 programmer was built from design by Derren Crome in Everyday Practical Electronics magazine (February 1996, pp 102).

I am sure the original veroboard programmer with four rectangular red LEDs on it is still around somewhere, but I can't find it at the moment. I later replaced that with a kit version based on the same design, which I still have.

The introduction of the electrically erasable versions brought this to hobbyists like the teenage me to be able to develop code and try it in real time.

This version did now had all the following features:

  • 1K EEPROM program memory
  • 36 registers
  • A single 8 bit timer
  • An external interrupt

I built lots of projects with those, including my final year degree project. That was a demonstration system for a way of controlling car lights with a single power bus and an optical cable. My test setup was a 4x3 sheet of plywood with two mini Metro taillights from the scrapyard and a few coils of fibre. I wish I had a camera in those days, no records of any of it unfortunately.

I still have a few bits of old project boards. I wonder where I salvaged the chips on this one from? 74LS04 from 1977, a ceramic 54LS138 from 1985. Only the PIC would have been new, the later PIC16F84.

I think this was a clock control board - I built a lot of clocks in those days. These ones used the larger PIC16F874 I think.

But we did an awful lot with those minimal features. It was a similar discipline to writing on an 8 bit computer. Every byte and every cycle counted. Every bit of lazy coding wasted time and space, both of which were precious.

When you think about it, the PICs were RISC processors, Reduced Instruction Set Computer, with 35 instructions. That's not too different to the standard 6502 with 56 instructions, and fewer registers and not even the single 8 bit timer.

I am sure writing under those constrains breeds better programmers. The old approach to "my code is running slow" was "rewrite it to be faster and more efficient". The modern approach is "specify more RAM and a faster processor".

Arduino

Roll on to the next generation, something like the ATmega328P found in Arduinos and the like.

That seemed to bring on a whole new wave of possibilities with it's neatly packages microcontroller and USB programmer all in one.

The ATmega328 and chips of that generation had a while load of more peripherals.

  • Two 8 bit times
  • A 16 bit timer
  • 6 channel ADC
  • USART
  • SPI
  • I2C (or rather TWI which is compatible as I2C is a licenced protocol)
  • Analog Comparator
  • 32K program memory
  • 2K SRAM

Such a world of possibilities.

Although, again, I built clocks.

One thing to note here is that each of those features had their own dedicated pins. There was one pin that could be RS232 TX. Most could be an IO pin, some could also be analogue inputs or external interrupt sources.

When designing things, you had to be aware that if you wanted to use SPI, then you had to use pins 16, 17, 18 and 19. That was sometimes a problem, specially when I often need an 8 bit wide port and usually find they are broken up with pins I need for serial or SPI etc.

AVR series

Things have moved on again. Microchip bought Atmel and brought a lot of PIC style things to the latest round of AVR microcontrollers, which now carry a Microchip logo.

They also have their own combined programmer and dev board, the Curiosity Nano series.

These have been quite useful, since I have never got on with their programmers like the MPLAB (should be) Snap (ped in half).

They are also small and cheap enough (~ £15) that you can just wire them into a project during development.

These have an embarrassment of peripherals compared to the lowly PIC16C84 and even the ATmega328P.

  • 128K program
  • 16K RAM
  • 512 bytes EEPROM
  • 4 x 16 bit timers
  • 12 bit timer
  • Real time clock
  • 3x USART
  • 2x SPI
  • I2C (TWI)
  • 10 Analogue inputs
  • 3 Analogue comparators
  • 1 Zero crossing detector
  • 18 channel touch controller

However, there is an important difference, these features are no longer tied to particular pins.

If you want to use an RS232 port, there are now three, so you can have your RS232 TX on pins 2, 10, 12, 16, 22 or 26.

The datasheets now have massive tables showing the various multiplexing options.

This is a bit of a double edged sword, all this flexibility means there is a lot more to configure to map the signals to the right pins.

There are also two new internal systems which can be incredibly powerful.

The Event System and the CCL (Configurable Custom Logic) system allow you to wire up some of those peripherals and pins in different ways.

Configurable Custom Logic

In it's simplest form, the CCL is a few gates of configurable logic, sort of like a mini GAL chip. You have multiple three input, one output blocks. You can do things like take three input pins and set an output high when one is low and the other two are high, or whatever, according to a pre-programmed truth table.

You can also add sequential logic like flip flops to these signals.

That can be useful, and can save a logic chip or two. I used this to remove the need for one of the flip flops in the Minstrel 4th (although I then used it for something else).

Where it becomes more interesting is there are some other inputs you can add to the logic, such as the output of timers etc.

Events

The event system is another way of wiring thing together, again, all behind the scenes requiring only setup code and stealing no cycles after that.

You can do things like get a timer to trigger the ADC to start an analogue conversion, you can get an external pin to trigger a timer, or count a pulse.

When I was first investigating the Mini VIC, I had one of these setup with timers generating the video sync, all does with this linked logic and no code other than the original setup. The horizontal sync counter would output the pulse at the start and clock the vertical sync counter, which would output it's own sync pulse at the appropriate point.

You can use also wire the event and CCL system together to do quite complex tasks, for example, you could have three pins that were ANDed together in the CCL and then sent to a timer via the event system to increment a counter.

You can also change things on the fly from code, so in the Minstrel 4D, I had the signal sent to the EAR pin configured as a CCL output. This could either be wired to the analogue comparator output, or it could be controlled by the output of a shift register clocking through data from SD card or loaded over serial.

But ....

With something like the ATmega328, it was fairly easy to set things like that up, as there were limited options, so once you enabled the RS232 USART, you know it was going to use pins 2 and 3 (although as is the law in this situation, there is no point in checking which is which as 50% of the time you it will be wrong anyway, RX-RX or RX-TX etc.)

Because of all the options in the AVR chips, various tools are provided to configure things for you.

I don't want to put you off here, but they don't always work. There seems to be an update every time you start up, and there is a whole new system every couple of years, and unfortunately none of them are perfect.

Having tried many of these at different times, and haven't found one that suits me yet (which I am sure is partly my fault).

The main issues I have found are:

  • Life cycle - as they move to new systems, the old ones stop being updated to add support for new devices
  • Bugs - with so many devices, and so many combinations of options, there are bound to be mistakes
  • Bloat - in order to support all these things, the code generated tends to be quite large and inefficient

Those may not be a problem for you (or indeed me), depending on the application. Often I want to be able to flip IO pins in a single cycle. However if the timing is not that important, the framework will generate nice commands like

  • LED_set_level(true);

Depending on the compile options, that might be optimised, but otherwise there is a lot of overhead with C function calls, saving lots of registers and them restoring them at the end.

I have found the best way for me is to use the tools to generate some code, and then try to pick through the dozens and dozens of files generated to find which bits I need to add to my simple C or assembler projects.

I think a good way to demonstrate this would to run through a real world example, with increasing complexity, to get to the functionality that I needed, and then condensing that to the few lines of assembler are actually important.

This post is already getting a bit long, so I will do that as a part 2.


Adverts

Lots of things built using microcontrollers are available from my Tindie Store. 

I can still ship worldwide. 

Currently it looks like Royal Mail to the US is working without having to pay tariffs (computer parts are excluded from the 10% so there is just a handling fee, which I pre-pay). There still may be delays or charges. We're all pawns in a petulant child's political games, but we've got to just keep going and try to make this stuff work.


Patreon

You can support me via Patreon, and get access to advance previews of development logs on new projects like the Mini PET II and Mini VIC and other behind the scenes updates. The part two to this post should be appearing there shortly. This also includes access to my Patreon only Discord server for even more regular updates.