Author Topic: Newbie questions about writing apps for microcontrollers  (Read 5132 times)

0 Members and 1 Guest are viewing this topic.

Offline woody

  • Frequent Contributor
  • **
  • Posts: 354
  • Country: nl
Re: Newbie questions about writing apps for microcontrollers
« Reply #25 on: July 21, 2022, 08:00:40 am »
To me an "advanced programmer" knows how the hardware works to some extend, and is able to come up with solutions to solve problems when they arise. And is also able to write something completely from scratch with just plain C or assembler. No libraries what so ever. Just your own code and understanding of what you are doing.

So true. I still remember the magic when I managed to light my first LED on a PIA connected to an 6800. Using assembler. And even today, when I start using a new-to-me CPU, the very first thing I do is connect a led and make it blink. Using C.
I dabbled with lots of alternatives like Arduino and made LEDs blink with them, but that never gives me the same feeling of total understanding and control that using a datasheet and assembler or C gives me.
 
The following users thanked this post: pcprogrammer

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4484
  • Country: nz
Re: Newbie questions about writing apps for microcontrollers
« Reply #26 on: July 21, 2022, 10:19:20 am »
And how did I learn programming. It started with basic on a TRS-80, but soon evolved to Z80 assembler and during my working live it went from 6502, 8051, 6800 etc assembler onto C/C++/C# and things like ASP, PHP, HTML, basic script, javascript, sql, etc. Programming is not in a language it is a skill.

Similar.

Actually, I started programming on TI (58, 59, then bought a 57 for myself: NZ$117 in 1979) and HP (67, 97) calculators. I touched a Pet and a Trash in shops and wrote '10 PRINT "I AM COOL":GOTO 10' on them. But the first serious contact was when my high school bought an Apple ][ at the end of my final year. Technically school had already finished, but the Math HoD phoned me and said "Bruce, this Apple ][ has arrived. Can you take it home for a week or two and figure it out and then tell me about it?". Sure. Incidentally I still visit that teacher sometimes, 42 years later. He is 99 now.

My first useful program was written in BASIC but called the "RWTS" (Read/Write Track Sector) machine code function in DOS. The program was a very basic but functional GUI disk sector hex editor, which I used to repair a number of disks, and I'm sure other people did too. I passed it on to the local Apple agent.

My second useful program replaced the keyboard input function. Or, I should say, wrapped it. My code (6502 machine code obviously) maintained a queue of names of text files to print, kept one disk sector of the current file in RAM, checked the RDY pin from the printer on its IO port, poked a byte at it if it was ready, then chained to the original keyboard input function. Even at that time the Seikosha GP80 30 CPS printer and the faster C-Itoh 8510 had a couple of lines of input buffer, so unless the BASIC program being run in the foreground was really CPU-bound the printer would be kept busy.

Not bad for a 100% self-taught 17 year old in the arse-end of the world, if I do say so myself :p
 

Offline tooki

  • Super Contributor
  • ***
  • Posts: 12594
  • Country: ch
Re: Newbie questions about writing apps for microcontrollers
« Reply #27 on: July 21, 2022, 04:07:27 pm »
Some people complain that things such as digitalWrite() take perhaps a µs or two longer than direct port writes because it has to translate a logical pin number to a physical pin number, and then convert that to a port address and mask.

Which is true enough, but totally irrelevant to the vast majority of users, who are doing things on a ms or longer time scale.

It might be interesting if there was a getPinPortAddress() and getPinMask() that could be called at startup and the values saved. But, having to load those those values from global variables each time instead of having them as hard-coded constants still wouldn't satisfy to moaners so ... whatever ...
While I completely agree with you that for the vast majority of use(r)s, it doesn't matter at all, the digitalWrite function is actually insanely slow for what it is: on a standard Arduino Uno, toggling a pin is about 18 times slower than direct port manipulation! But of course, there are libraries for faster pin manipulation, or you can just manipulate them yourself.

The flip side is that Arduino makes it almost foolproof to dip your toes, and I think the satisfaction of getting something running quickly is a great way to get people interested in embedded programming. The talented ones will still advance quickly, the totally untalented ones can still be happy making things blink, and somewhere-in-the-middle coders like me still get enough satisfaction to go on and learn more, rather than getting stuck at the huge hurdle that traditional MCU toolchains present, which would have put me off it for sure.
 

Offline ozcar

  • Frequent Contributor
  • **
  • Posts: 342
  • Country: au
Re: Newbie questions about writing apps for microcontrollers
« Reply #28 on: July 21, 2022, 06:13:23 pm »
Some people complain that things such as digitalWrite() take perhaps a µs or two longer than direct port writes because it has to translate a logical pin number to a physical pin number, and then convert that to a port address and mask.

Some of the time taken is due to making sure that timer PWM is not active for the pin every time.

It might be interesting if there was a getPinPortAddress() and getPinMask() that could be called at startup and the values saved.

You mean something different to the portOutputRegister() and digitalPinToBitMask() macros?

 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4306
  • Country: us
Re: Newbie questions about writing apps for microcontrollers
« Reply #29 on: July 21, 2022, 09:27:12 pm »
Quote
the digitalWrite function is actually insanely slow ... about 18 times slower than direct port manipulation!
Well, setting/clearing a pin with direct port manipulation is a single sbi or cbi instruction, so it doesn't take much to multiply the execution time.  And that single instruction only works for a constant pin and a constant value.  As soon as you want variables there, you're talking about loading a 16bit address into a register, reading, modifying, and writing the port via that pointer, so you're looking at about 6x slower than sbi/cbi.  Add the pin mapping and checking for PWM, plus function call overhead, and ~20 instructions doesn't seem so bad...

(The frustrating part is the code on newer processors that goes to significant trouble to preserve AVR-like behavior.  "digitalWrite(pin, 1) turns on the input pullup if the pin is in input mode" is just how the AVR works.  But it takes special checks and much more convoluted code to make it happen on an ARM...)
 
The following users thanked this post: tooki

Offline tooki

  • Super Contributor
  • ***
  • Posts: 12594
  • Country: ch
Re: Newbie questions about writing apps for microcontrollers
« Reply #30 on: July 21, 2022, 09:57:34 pm »
(The frustrating part is the code on newer processors that goes to significant trouble to preserve AVR-like behavior.  "digitalWrite(pin, 1) turns on the input pullup if the pin is in input mode" is just how the AVR works.  But it takes special checks and much more convoluted code to make it happen on an ARM...)
I guess it’s frustrating if you expect each MCU’s “native” behavior, but it makes total sense for code portability for it to behave like AVR. As I said, I think that’s a huge advantage of the Arduino framework, even if it does entail some compromises.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 4484
  • Country: nz
Re: Newbie questions about writing apps for microcontrollers
« Reply #31 on: July 22, 2022, 01:07:03 am »
You mean something different to the portOutputRegister() and digitalPinToBitMask() macros?

Well, there ya go!  They thought of everything. Plain digitalWrite() has always been fast enough for my needs, so I hadn't investigated further.
« Last Edit: July 22, 2022, 01:09:19 am by brucehoult »
 

Online westfw

  • Super Contributor
  • ***
  • Posts: 4306
  • Country: us
Re: Newbie questions about writing apps for microcontrollers
« Reply #32 on: July 22, 2022, 02:42:09 am »
Quote
It makes total sense for code portability for it to behave like AVR.
IMNSHO, there weren't enough applications written before pinMode(pin, INPUT_PULLUP) was implemented, to justify carrying that behavior forward, rather than "insisting" that people convert to the more explicit API.

Extending the portability requirement quickly gets ridiculous (like the PORT emulation on the 4809 boards, which attempts to coerce PORTB=x into some scatter/gather of the pins that are actually connected where the originals were.  (which would be a sort-of neat C++ hack, if people weren't using the direct ports for speed purposes, and the emulation wasn't horribly (and I think of necessity) slow (though faster than N*DigitialWrite()))
 

Offline Nominal Animal

  • Super Contributor
  • ***
  • Posts: 6864
  • Country: fi
    • My home page and email address
Re: Newbie questions about writing apps for microcontrollers
« Reply #33 on: July 22, 2022, 04:37:08 am »
On many 32-bit ARM microcontrollers one can write code for in the Arduino environment – my favourites being the Teensies by PJRC.com – each GPIO bank tends to be either 16 or 32 bits/pins wide, and usually have output, set, clear, and toggle registers.

Writing a value to the output registers sets all pins in that bank to the specified states.
Writing a value to the other three registers only affects the pins corresponding to bits set in the written value.  Writing to the set register, those pins are set high.  Writing to the clear register, those pins are set low.  Writing to the toggle register, those pins will have their state toggled between high and low.

(This assumes the ones whose state will change are outputs.  Some do use the output state for input pullup enable or similar, when the affected pin is an input.)

The toggle is most interesting to me, because it allows one to treat any subset of a bank as a parallel bus without affecting any of the other pins in the same bank.  The key to setting the "bus" to a specific state is remembering the state it has been previously set to, since exclusive-OR between the current state and the desired state yields the toggle set.  Since many of these ARM MCUs have DMA capabilities, and the aforementioned operation is trivial to do when filling in a buffer of (future) bus states, it makes for an excellent parallel bus DMA mechanism.

Of course, the annoying thing is that rarely do the pins you can use for the parallel bus correspond to bits 0..N-1 in the bank.  Every GPIO pin tends to have a set of alternative functions (like say SCK pin of a SPI bus, SDA or SCK of an I2C bus, PWM from a specific timer, and so on).  One solution to this is to use a lookup array with N 32-bit words, with index corresponding to bus state, and output corresponding to GPIO bank bits.  For N>8, the arrays become too large, but instead of a single lookup, one can use multiple arrays, each dealing with a subset of the bus width.  For example, if one has a 16-bit parallel bus, you can pick any 16 pins in a single bank, in any order, and do one lookup each into two separate 256-entry lookup arrays, that only need 2048 bytes of memory total.  (A single lookup array would need 262144 bytes of memory.)  With four lookups and a 16-bit parallel bus, you only need 128 bytes for the four tables, 16 entries in each.



Right now, I'm playing with a BuyDisplay ER-TFT028A2-4 display module, which provides both parallel and serial interfaces to its ILI9341 controller (controlling the 2.8" 240×320-pixel 18-bit color IPS panel on it), with a Teensy 4.0 microcontroller.  Since I will be doing framebuffery pixel-manipulation stuff, splitting the 18-bit parallel bus to three separate 6-bit buses (RGB, each with 2⁶=64 intensity levels), I also only need 3 lookup tables with 64 entries of 32-bit words each –– except that none of the banks really have enough GPIO pins for me to use, so I'll have to split them into different banks.

(The framebuffery pixel-manipulation stuff means things where I will be manipulating the pixel color in a way that I will end up with some kind of value where I can easily pick off the 6 most significant bits for each color component.  Mapping them through a lookup table is a minimal extra cost, since I'll be doing something like four multiplications per pixel (for color blending) anyway.  All I want to be able to do, is do all this faster than the refresh on the display module, so I won't see annoying tearing on it.)

However, one must also send 8-bit commands and data to the display, and those cover one 6-bit bus, plus two least significant bits from another bus.  So, if I could put 12 pins in the same bank, I could have both the three RGB-lookup tables (768 bytes total) and the 256-entry (1024-byte) command/data lookup table making things easy.

So, what I have been doing, is experimenting with the pin selection!  (And also the backlight for the display module.  I do code well, but on the electronics side, I'm rather a beginner hobbyist.)  Of course, the pins on the microcontroller evaluation/development boards is not according to the internal bank system, so one ends up with spreadsheets with pin mappings, their alternate functions, and playing with the numerous options on which pins to use for which purpose.

Often, the microcontroller processors –– especially those using BGA footprints –– have many more possible outputs than are exposed on the cheap evaluation/development boards one uses with Arduino, making that kind of selection annoying and frustration, which is why people doing anything like this will very soon move on to designing their own boards, so they have more options in picking which pin to use for which purpose.



The above means that if you want your Arduino code to be portable, you must stick to the Arduino (library) features, and not use the hardware directly, as the direct hardware access (through ports and registers) will vary from microcontroller to microcontroller.  On the other hand, some of the more interesting stuff (like the parallel bus to a display module above) really needs hardware access, and is not as easily portable at all.

As a result, I would say it is very important to play with all kinds of peripherals and sensors and breakout boards, and understand how they are controlled and communicated with.  Not just "I used this library; that's all I know", because that only teaches you how to use libraries written by others, you do need to be interested in finding out exactly how stuff happens, too.

While I do use Arduino for experiments and stuff I want those that use Arduino to use too, I do kinda-sorta like bare-metal development more.  I don't see them as one excluding the other; they're just different environments, and I use both.  In the mean time, there are others like PlatformIO that can use Arduino libraries, but do not rely on it or its IDE, that one should probably also experiment with too, if they have a supported microcontroller.

As in all programming, documentation should never be overlooked, either.  Always write comments that describe your intent, not what the code does.  (Anyone can read the code and see what it does, but the code does not tell what it is trying to accomplish, how, nor why.)  And documentation showing wiring and real-life test cases, rationale for the design choices, and so on, is always useful.  So practice that, too, from the get go.  It is not something you can just pick up later on, and "for now concentrate on the code": it becomes much, much harder to learn to do afterwards!  I know from hard-fought experience.  Make good documentation a habit from the get go, and you'll end up being very happy you did so, guaranteed.
 
The following users thanked this post: tooki, pcprogrammer

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 4230
  • Country: gb
Re: Newbie questions about writing apps for microcontrollers
« Reply #34 on: July 22, 2022, 08:32:10 am »
While I do use Arduino for experiments and stuff I want those that use Arduino to use too, I do kinda-sorta like bare-metal development more.  I don't see them as one excluding the other; they're just different environments, and I use both.

Well said. Not the same, different stuff, that can solve different needs.
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 4230
  • Country: gb
Re: Newbie questions about writing apps for microcontrollers
« Reply #35 on: July 22, 2022, 09:03:05 am »
at the moment I am writing a polymorphic arbitrary linear system solver through pivoting-Gauss reduction; Wait!! What??
Code: [Select]
          A * x = b
          x = ?
A is a matrix, it can be a sparse matrix; x  and b are vectors

size(..) = custom defined, even at run-time
type..) = custom defined { floating point, fixed point, complex fp64, complex fx ... }

so you have to define methods and operators for each type, and write the solver in an abstract way ... that's the job for C++ (and probably on a PC), but I want to use C.

That's definitively not what you would like to do with MPUs ... even because there is a price to pay(1) to have this level of abstraction.


To say: different needs, different tools  :-//


(1) more CPU-cycles and more code size
« Last Edit: July 22, 2022, 12:47:56 pm by DiTBho »
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf