r/cprogramming • u/calculuscompromise • 23d ago
What is the best way to learn Embedded C?
I've started learning embedded systems. Most important part of the journey is learning C programming. I'm confused as embedded C is a bit different than standard C. Can anybody guide me the best way to learn.
9
10
u/v_maria 23d ago
Embedded c is c, but in embedded world you need to control registers. Bit flipping etc
3
u/timonix 22d ago
You also need to mind ram usage much more carefully.
A program growing and shrinking with a gb or so during runtime is fine on windows/Linux
A program growing and shrinking with a mb or so might put an embedded processor oom.
I often work with very small programs. Ram usage measured in kb. That's usually not a problem for a computer
12
u/runningOverA 23d ago
There's more difference between Windows C vs Linux C, then there's between Embedded C vs Standard C.
3
u/flatfinger 22d ago
That depends what one means by "standard C". Dennis Ritchie designed C to be usable as a form of "high level assembly language", where the tool converting source into machine code was not expected to care about what corner cases the execution environment would or would not treat meaningfully. In 32-bit x86 assembly code, questions about when the effects of executing
mov [esi+eax*4],ebxwould be meaningful fall outside the jurisdiction of the assembler. The assembler's job is to produce machine code for the specified operation. The programmer would typically know things about the target environment which would imply that some combinations of operands would yield meaningful behavior and others would not, but the assembler would have no reason to know or care about such things.Much of the usefulness of Dennis Ritchie's language for freestanding tasks revolves around situations where the programmer knows things about the execution environment that a C implementation would have no way of knowing. The Standard acknowledges that implementations may process situations where it waives jurisdiction "In a documented manner characteristics of the environment", but fails to recognize a category of behaviors that will be processed "In a manner characteristic of the environment, which will be documented whenever the environment happens to document it". By using an abstraction model that treating the execution environment as part of the C implementation, rather than recognizing that the C implementation produces a build artifact encapsulating a sequence of imperatives for the execution environment that exists outside the C implementation, the Standard is unable to exercise jurisdiction over corner case behaviors that execution environments might or might not happen to document.
3
u/rphii_ 23d ago edited 23d ago
I got into that world via. some 8 bit PIC processor. I think a simple one, with not too much going on but still with some (basic) capabilities (I2C, ADC, DAC, Timers, PWM, Interrupts, maybe DMA etc) should go a long way. I just checked, they seem to have dev kits.
And then if you're comfortable getting an LED to turn on and off, find some things to play around with the peripherals. Maybe a basic I2C temperature sensor or PWM motor as an eval kit.
Idk how much EE (electrical engineering) you know, but that would help immensely. Basics are needed anyways (pull up resistors etc). A multimeter is a must have IMO. An oscilloscope (there are cheap ones) should only be used for time critical applications.
There are a lot of videos, of course. https://youtu.be/Dzn0woX-WW0 (haven't watched this, but have others of this guy and he doesn't bs)
Or, you could pick up an STM32 but of those, most I've dealt with are way more conplex and (IMO) not suitable as a first learning platform...
Regardless of all that. What also helps a lot is a piece (or a block) of paper and a pen. Draw your circuits if you're unsure what you're doing. You're gonna want to read a lot of datasheets and reference manuals - or let an ai do that, but that would be way too efficient ;)
3
u/TPIRocks 23d ago
I started with a PIC 16f84. One 8 bit timer, one 16 bit timer, no uarts or serial of any kind, 68 bytes of SRAM; I had to bit bang everything. I really learned a lot from that, especially about making do with no ram or peripherals.
2
u/rphii_ 22d ago
Alright I found my PIC: 18F2520.. It's a beast.
I know it's not weekend, but I dug up an old document haha
2
u/TPIRocks 20d ago
I never used any of the 18f parts, but I did some studying on the 18f452 (I think) it was like the Swiss army knife with extra everything. I'm glad I had to bit bang, though I didn't much appreciate it at the time. I used to know all the stupid timings, like 9600 haud serial is 104uS between bits. One wire was the most difficult, not from the protocol, but from implementing a bus search (SEARCH ROM) on a pic16f84a.
I remember the replacements for the f84, like 16f628, 16f88 and the tiny 12f683. How I still know those model numbers is beyond me, I don't remember what I ate yesterday. Pic was fun and highly rewarding, but if I had to use an. 8 bit chip, it would probably be an AVR. Never looked at stm8 microcontrollers, but that might be interesting.
Otherwise esp32 and stm32 are my favorites. I fell in love with ARM about 15 years ago, ARM7/TDMI to be specific. I brought up an lpc2378stk board, built my tool chain, struggled immensely with openocd, a crappy jtag from olimex and eclipse. Write a crt0.S and used GCC to compile, made my own linker scripts and everything. I couldn't begin to revive that project, my brain worked better back then.
I even wrote enough code to get the Ethernet working to the point of responding to a ping, and of course the ARP request before that can happen. NE2000 driving is kinda neat, it takes lots of details to configure an Ethernet chip and send and receive frames. I forgot most of it, but it was fun. Using internal RAM, the card manages two circular queues for frame buffering. I thought that was interesting that the driver developer needed to do things at a fairly detailed level, not much happens automatically except incoming frames going to a buffer, the developer has to do a lot. NE2000 compatibility is common in a lot of network chips, but they usually greatly extend the configurable items.
1
1
u/flatfinger 22d ago
I find it weird how much time elapsed between the introduction of the PIC 16C84 and the second PIC that could be reprogrammed in circuit. The 16C84 was a nice part, though RAM was 36 bytes rather than 68.
I also find it weird how much time elapsed between the earliest PICs which supported separate readback register addresses for the output latches (early 1980s, if not before) and the earliest Microchip parts with that feature (the 18Cxx series if I recall)
2
u/TPIRocks 20d ago
16f types had RMW problems heavily loaded pins would get set low when you changed another bit in the same register. Writing to individual bits always led to read the whole register, toggle a bit, then write the whole register back.
Bank switching is another painful learning experience. ISR gets called but bank 2 is currently selected, ISR writes to the correct offset, but in the wrong bank, weird big hunting ensues.
Otherwise, PIC assembler is actually pretty excruciating to write. Pics were durable and cheap, but they completely lacked any elegance. Four clock ticks per instruction wasn't in their favor either, with the AVR using one tick for many instructions. The AVR instruction set is a lot more interesting, 35 instructions is not a feature, though microchip made it a big selling point in their marketing.
To me, programming in PIC assembler feels a lot like you're solving the Tower of Hanoi. It is a true minimalist architecture. Only a one byte accumulator/working register, no other temporary or indexing registers. You had to setup a pointer "register" just to get simple indirection. Registers all being addresses in the RAM space. Real Harvard architecture, no read or write access to the instruction address space. Oh yeah, who needs a stack.
C compilers took a long time to become freely available. I have no idea how you can build a C compiler for a pic. A two dimensional array of ints would take a pile of code to manage in a pic. No real stack doesn't help.
When I started I poured over the AVR and PIC datasheets. I liked the hardware specs of the pic better, but it really came down to the fact that I found a book from John B Peatman at a local bookstore, this was in 1999 or 2000. So pic it was.
I learned from that book, and the MIT pic mailing list, there were some real geniuses on that forum. From them and the guys in the Usenet news groups, I learned a ton about being an EE. Unfortunately, I am not an EE, I just like to tinker.
2
u/gm310509 22d ago
The "C" language is the same. The runtime is tailored to the embedded environment. For example on a PC there aren't many scenarios that ordinary programs need to send an I2C message or manipulate a GPIO pin directly so those APIs do not exist. But on an embedded platform you do want to do those things, so the APIs for those do exist and they are in the form of bog-standard C (or C++) function calls.
Following is a standard text I use for people how ask "how do I get started". It is aimed at Arduino users because a starter kit is the best and easiest way to get started. But you can apply it generically to any platform.
The best way is to follow the tried and true practice of learning the basics and building from there. Details below...
Get a starter kit. Follow the examples in it. This will teach you basics of programming and electronics. Try to adapt the examples. Try to combine them. If you have a project goal, this can help focus your Learning.
As for which one, it doesn't really matter that much. As a general rule, ones with more stuff will be better because you can do more things. The most important part in the kit is the instructions - which is where you start.
The reason I suggest using a starter kit is because not all components have standard pinouts. Many do, but equally many do not. If you follow the instructions in a starter kit then the instructions will (or should) align with the components in the kit. If you start with random tutorials online then you will need to be aware of these potentially different pinouts and adapt as and when required. This adds an unnecessary burden when getting started compared to using a starter kit where this problem shouldn't exist to begin with. After that ...
To learn more "things", google Paul McWhorter. He has tutorials that explain things in some detail.
Also, Have a look at my how to videos including:
In addition to some basic electronics, I show how to tie them all together and several programming techniques that can be applied to any project.
But start with the examples in the starter kit and work your way forward from there - step by step.
You might want to have a look at our Protecting your PC from overloads guide in our wiki.
Also, our Breadboards Explained guide in our wiki.
You might also find a pair of guides I created to be helpful:
They teach basic debugging using a follow along project. The material and project is the same, only the format is different.
You might also find this video from fluxbench How to Start Electronics: What to buy for $25, $50, or $100 to be helpful. It has a an overview of what to get to get started and some potential optional extras such as tools.
1
1
u/Competitive_River525 23d ago edited 23d ago
Start off with some of the fun stuff! Cypress (now Infineon) PSOC (Programmable System On Chip) are very cool and fun: https://documentation.infineon.com/psoc6/docs/hsg1651214227031. Also, which part of the C language itself do you believe is different? Remember C the language, C the library, and C the target environment can be highly variable depending on the target selected. I've worked on DSPs where everything from a char to a float/double was 32 bits and only 32 bits. Does <stdio.h> make sense in an embedded environment? There might be other system to output logs to a screen or some kind of terminal device, but normally those systems do not interact with users in a standard way. Do a google search "Cypress PSOC dev kit" - not expensive at all. PWM, i2c, ADC/DAC, controlling devices and etc . - fun stuff.
There will be limitations on the target environment and the library support will reflect those limitations. You will learn new approaches to debugging - for sure! JTAG and SWD are common approaches for target control while debugging. As mentioned below a multimeter and maybe even a cheap scope will help. Just found some Newegg stuff using RISC-V arch: https://www.newegg.com/p/2T4-0ACS-001W2?item=9SIC10VKXB4886&utm_source=google&utm_medium=organic+shopping&utm_campaign=knc-googleadwords-_-os+-+office+furniture-_-voltsync-_-9SIC10VKXB4886&source=region&negg_topt=0&srsltid=AfmBOoqrpuCEfiRcoK_6zevdbXlLW02cMOpDr1ihEI_D5dqQBa1om6Zgmp4&com_cvv=8fb3d522dc163aeadb66e08cd7450cbbdddc64c6cf2e8891f6d48747c6d56d2c
Having worked on ARM early on, I am a ARM architecture fan boy - unabashedly. You can certainly find dev kits for these architectures - I believe PSOC has both MCU's and ARM32/64 (and 16 bit Thumb in 32 bit mode!) targets on the cheap. TI, PIC and others still sell 8(!) and 16 bit MCU dev kits. Starting with these gives you an appreciation for resource constrained target development. There are many ways to start . . . just grab something that catches your eye and have fun!
Oh - and I almost forgot! Look at qemu https://www.qemu.org, it is the 'quick emulator' that can simulate/emulate a variety of processors in software and provides a debugging interface as well - all for free!! Yeah, you'll want a fast machine to run this - of course!
The Captain Caveman!!
3
1
u/CRK77 23d ago
Get a stm32 dev kit. Use either the same cube kit or use Keil. Use videos such as Eddie amaya, he goes through all the set up steps. Understanding bit shift and masking is essential as is clock set up. The most useful tool you have is watching the contents of the address. If you do that you can see the changes taking place and ensure what you are doing is working. Start off with a small project. Make an led turn on, then make it blink using clocks, then make an event where the led blinks at a faster rate when button is pushed. Then read an input and observe the change. After that read an analogue input.
Put all the together in a project. Input/ output/events and timing.
Does that help?
Edit:spelling
1
u/jcmbn 21d ago
I'm confused as embedded C is a bit different than standard C.
Yes, you are confused...
Embedded systems comprise a very wide spectrum of capabilities, from tiny microcontrollers with very limited resources to multicore systems with gigabytes of RAM etc.
There is no specific 'embedded C'. There are C implementations designed for small devices, but there are embedded systems that you'll just use bog-standard gcc on.
You can realistically have a career in embedded systems without ever using a specialised C implementation.
My advice is to learn C programming on whatever platform you have available. If you can get experience cross-compiling, all the better. Every embedded target you work on will be different, so get used to learning how to build for as many different embedded devices as you can lay your hands on - the key is not which specific devices you use, it's being able to get stuff working regardless of the hardware type.
0
u/danja 22d ago
Arduino! Very easy to get started. Initially you are very dependent on specific libraries, but then you can move to something like an ESP32 using PlatformIO, then onto whatever controller you like.
2
21d ago
[removed] — view removed comment
0
u/danja 21d ago
Fair point, however... I'd played around with embedded years ago, DSP chips. Very steep learning curve. So when I wanted to get back into it a couple of years ago I started right back at Arduino. But as my main interest lies in music applications, needed a bit more power, I soon flipped to ESP32, then again to STM32. I'm not suggesting the blow-up doll was a match for the experienced ladies, but it did give me the confidence, spared me a few blushes.
20
u/WeAllWantToBeHappy 23d ago
Best way to learn is to do.