u-boot - control characters support disabled - u-boot

To stop autoboot we have 2 ifdef (CONFIG_AUTOBOOT_STOP_ [STR2 || STR1] ). Which is very easy and straightforward to implement. Halting a boot with single “Keystroke” or with a pharase is having its own advantages to the user. But, why contole key support is ignored say like [ctrl + anykey ] combination. Especially, BIOS vendors prefer at least simultaneous pressing of 2 or more keys to halt the boot. Any specific reasons to avoid this. Other than simplicity is there any specific reason to stick on this.

The CTRL key is a modifier. And CTRL+KEY combos register as normal KEY press event with additional flags set to indicate the status of modifier keys. Read about modifiers in keyboard drivers in the Linux kernel keyboard driver documentation.
Also check this excellent article on how keyboards work.
Handling all the modifiers requires additional complexity in the code. Bootloaders run in a severely constrained environment. Especially on embedded systems(which u-boot is meant for), it is very common to expect the entire u-boot to load and run within 64/128K of RAM (the binary + stack).
Considering the fact that we have >50 unique keys on our keyboards to bang before we require using modifiers, software support for them is usually not implemented in u-boot.

Related

Is it possible to create a PIC firmware binary that supports multiple different microcontrollers?

Due to the current chip shortage, I have had to purchase PIC microcontrollers that have a different specification to what was initially designed.
Initial: PIC24FJ256GA606
Revision 1: PIC24FJ512GA606
Revision 2: PIC24FJ1024GA606
In this instance, the microcontrollers are within the same family but have different size of memory.
Initially, the binary was created to support multiple product variants and they all use this microcontroller (using hardware pins to define the type of product and thus the software features it supports). I would like to continue with a single binary but to be able to support the different microcontrollers specified above.
We flash the microcontrollers using a PICKIT 4 during manufacturing.
A custom bootloader is also flashed onto the microcontroller during manufacturing to allow the firmware update procedure to be is driven by another PIC microcontroller out in the field (it's a distributed system connected by RS-485).
I use MPLAB X IDE for development and buildings production binaries.
I guess the key question is about if this is even possible?
If so, then how would I achieve creating the single binary that supports multiple processors?
Normally a single binary should only correspond to the specific controller. Because especially Microchip has really wide variaty of microcontrollers. But as you mentioned in your question:
In this instance, the microcontrollers are within the same family but have different size of memory.
You can slightly use the same binary as long as you select the hardware very carefully. I mean if those 3 different models has the same pin mapping but some has less or some has more, then you would select the common corresponding pins for the I/O functions wherever possible. Since those devices are from the same family they must have common IO pins with the same port and pin numbering.
If those similarities including of that the internal registers are enough for the functionality of your system, you can use the same binary for those 3 or more devices as long as you select the right hardware very carefully and none of the functions remain without touching its hardware.
But it is very hard to say the same for the others that are not belong to a series in the same family. In this case you can check the hardware similarities for each functionality of your system. If that micro provides the same hardware, then you can go and firstly give it a try to see whether it will be programmed and then it will funtion in the same way. After making sure enough you can add that model in your usable models list, too.
Hope this give you a helpful idea.
For two microcontrollers to have compatible binaries, they need to fulfil the following:
The CPU cores must have identical Instruction Set Architecture. Be aware that the term "code compatible" by the manufacturer might only mean that two parts have the same ISA and are compatible on the assembly language level, as long as no peripherals or memories are used...
In case they have different memory sizes, the part with larger memory must be a superset of the part with smaller memory and they must map memory to the same addresses.
All hardware peripherals used must be identical and any peripheral routing registers used must also be identical. Please note that the very same core of the same family but with a different package and pin routing might mean that peripheral routing registers must be set differently.
There can be no check of MCU partnumber registers etc inside the firmware, nor can there be any in the flash programming equipment.
In general this means that the MCUs must be of the very same family and the manufacturer must guarantee that they are replaceable.
You can very likely switch between different temperature spec parts of the same model and between automotive/non-automotive qual parts of the same model without changing the code.

C external memory corruption detection and correction libraries? [duplicate]

We are compiling an embedded C++ application that is deployed in a shielded device in an environment bombarded with ionizing radiation. We are using GCC and cross-compiling for ARM. When deployed, our application generates some erroneous data and crashes more often than we would like. The hardware is designed for this environment, and our application has run on this platform for several years.
Are there changes we can make to our code, or compile-time improvements that can be made to identify/correct soft errors and memory-corruption caused by single event upsets? Have any other developers had success in reducing the harmful effects of soft errors on a long-running application?
Working for about 4-5 years with software/firmware development and environment testing of miniaturized satellites*, I would like to share my experience here.
*(miniaturized satellites are a lot more prone to single event upsets than bigger satellites due to its relatively small, limited sizes for its electronic components)
To be very concise and direct: there is no mechanism to recover from detectable, erroneous
situation by the software/firmware itself without, at least, one
copy of minimum working version of the software/firmware somewhere for recovery purpose - and with the hardware supporting the recovery (functional).
Now, this situation is normally handled both in the hardware and software level. Here, as you request, I will share what we can do in the software level.
...recovery purpose.... Provide ability to update/recompile/reflash your software/firmware in real environment. This is an almost must-have feature for any software/firmware in highly ionized environment. Without this, you could have redundant software/hardware as many as you want but at one point, they are all going to blow up. So, prepare this feature!
...minimum working version... Have responsive, multiple copies, minimum version of the software/firmware in your code. This is like Safe mode in Windows. Instead of having only one, fully functional version of your software, have multiple copies of the minimum version of your software/firmware. The minimum copy will usually having much less size than the full copy and almost always have only the following two or three features:
capable of listening to command from external system,
capable of updating the current software/firmware,
capable of monitoring the basic operation's housekeeping data.
...copy... somewhere... Have redundant software/firmware somewhere.
You could, with or without redundant hardware, try to have redundant software/firmware in your ARM uC. This is normally done by having two or more identical software/firmware in separate addresses which sending heartbeat to each other - but only one will be active at a time. If one or more software/firmware is known to be unresponsive, switch to the other software/firmware. The benefit of using this approach is we can have functional replacement immediately after an error occurs - without any contact with whatever external system/party who is responsible to detect and to repair the error (in satellite case, it is usually the Mission Control Centre (MCC)).
Strictly speaking, without redundant hardware, the disadvantage of doing this is you actually cannot eliminate all single point of failures. At the very least, you will still have one single point of failure, which is the switch itself (or often the beginning of the code). Nevertheless, for a device limited by size in a highly ionized environment (such as pico/femto satellites), the reduction of the single point of failures to one point without additional hardware will still be worth considering. Somemore, the piece of code for the switching would certainly be much less than the code for the whole program - significantly reducing the risk of getting Single Event in it.
But if you are not doing this, you should have at least one copy in your external system which can come in contact with the device and update the software/firmware (in the satellite case, it is again the mission control centre).
You could also have the copy in your permanent memory storage in your device which can be triggered to restore the running system's software/firmware
...detectable erroneous situation.. The error must be detectable, usually by the hardware error correction/detection circuit or by a small piece of code for error correction/detection. It is best to put such code small, multiple, and independent from the main software/firmware. Its main task is only for checking/correcting. If the hardware circuit/firmware is reliable (such as it is more radiation hardened than the rests - or having multiple circuits/logics), then you might consider making error-correction with it. But if it is not, it is better to make it as error-detection. The correction can be by external system/device. For the error correction, you could consider making use of a basic error correction algorithm like Hamming/Golay23, because they can be implemented more easily both in the circuit/software. But it ultimately depends on your team's capability. For error detection, normally CRC is used.
...hardware supporting the recovery Now, comes to the most difficult aspect on this issue. Ultimately, the recovery requires the hardware which is responsible for the recovery to be at least functional. If the hardware is permanently broken (normally happen after its Total ionizing dose reaches certain level), then there is (sadly) no way for the software to help in recovery. Thus, hardware is rightly the utmost importance concern for a device exposed to high radiation level (such as satellite).
In addition to the suggestion for above anticipating firmware's error due to single event upset, I would also like to suggest you to have:
Error detection and/or error correction algorithm in the inter-subsystem communication protocol. This is another almost must have in order to avoid incomplete/wrong signals received from other system
Filter in your ADC reading. Do not use the ADC reading directly. Filter it by median filter, mean filter, or any other filters - never trust single reading value. Sample more, not less - reasonably.
NASA has a paper on radiation-hardened software. It describes three main tasks:
Regular monitoring of memory for errors then scrubbing out those errors,
robust error recovery mechanisms, and
the ability to reconfigure if something no longer works.
Note that the memory scan rate should be frequent enough that multi-bit errors rarely occur, as most ECC memory can recover from single-bit errors, not multi-bit errors.
Robust error recovery includes control flow transfer (typically restarting a process at a point before the error), resource release, and data restoration.
Their main recommendation for data restoration is to avoid the need for it, through having intermediate data be treated as temporary, so that restarting before the error also rolls back the data to a reliable state. This sounds similar to the concept of "transactions" in databases.
They discuss techniques particularly suitable for object-oriented languages such as C++. For example
Software-based ECCs for contiguous memory objects
Programming by Contract: verifying preconditions and postconditions, then checking the object to verify it is still in a valid state.
And, it just so happens, NASA has used C++ for major projects such as the Mars Rover.
C++ class abstraction and encapsulation enabled rapid development and testing among multiple projects and developers.
They avoided certain C++ features that could create problems:
Exceptions
Templates
Iostream (no console)
Multiple inheritance
Operator overloading (other than new and delete)
Dynamic allocation (used a dedicated memory pool and placement new to avoid the possibility of system heap corruption).
Here are some thoughts and ideas:
Use ROM more creatively.
Store anything you can in ROM. Instead of calculating things, store look-up tables in ROM. (Make sure your compiler is outputting your look-up tables to the read-only section! Print out memory addresses at runtime to check!) Store your interrupt vector table in ROM. Of course, run some tests to see how reliable your ROM is compared to your RAM.
Use your best RAM for the stack.
SEUs in the stack are probably the most likely source of crashes, because it is where things like index variables, status variables, return addresses, and pointers of various sorts typically live.
Implement timer-tick and watchdog timer routines.
You can run a "sanity check" routine every timer tick, as well as a watchdog routine to handle the system locking up. Your main code could also periodically increment a counter to indicate progress, and the sanity-check routine could ensure this has occurred.
Implement error-correcting-codes in software.
You can add redundancy to your data to be able to detect and/or correct errors. This will add processing time, potentially leaving the processor exposed to radiation for a longer time, thus increasing the chance of errors, so you must consider the trade-off.
Remember the caches.
Check the sizes of your CPU caches. Data that you have accessed or modified recently will probably be within a cache. I believe you can disable at least some of the caches (at a big performance cost); you should try this to see how susceptible the caches are to SEUs. If the caches are hardier than RAM then you could regularly read and re-write critical data to make sure it stays in cache and bring RAM back into line.
Use page-fault handlers cleverly.
If you mark a memory page as not-present, the CPU will issue a page fault when you try to access it. You can create a page-fault handler that does some checking before servicing the read request. (PC operating systems use this to transparently load pages that have been swapped to disk.)
Use assembly language for critical things (which could be everything).
With assembly language, you know what is in registers and what is in RAM; you know what special RAM tables the CPU is using, and you can design things in a roundabout way to keep your risk down.
Use objdump to actually look at the generated assembly language, and work out how much code each of your routines takes up.
If you are using a big OS like Linux then you are asking for trouble; there is just so much complexity and so many things to go wrong.
Remember it is a game of probabilities.
A commenter said
Every routine you write to catch errors will be subject to failing itself from the same cause.
While this is true, the chances of errors in the (say) 100 bytes of code and data required for a check routine to function correctly is much smaller than the chance of errors elsewhere. If your ROM is pretty reliable and almost all the code/data is actually in ROM then your odds are even better.
Use redundant hardware.
Use 2 or more identical hardware setups with identical code. If the results differ, a reset should be triggered. With 3 or more devices you can use a "voting" system to try to identify which one has been compromised.
You may also be interested in the rich literature on the subject of algorithmic fault tolerance. This includes the old assignment: Write a sort that correctly sorts its input when a constant number of comparisons will fail (or, the slightly more evil version, when the asymptotic number of failed comparisons scales as log(n) for n comparisons).
A place to start reading is Huang and Abraham's 1984 paper "Algorithm-Based Fault Tolerance for Matrix Operations". Their idea is vaguely similar to homomorphic encrypted computation (but it is not really the same, since they are attempting error detection/correction at the operation level).
A more recent descendant of that paper is Bosilca, Delmas, Dongarra, and Langou's "Algorithm-based fault tolerance applied to high performance computing".
Writing code for radioactive environments is not really any different than writing code for any mission-critical application.
In addition to what has already been mentioned, here are some miscellaneous tips:
Use everyday "bread & butter" safety measures that should be present on any semi-professional embedded system: internal watchdog, internal low-voltage detect, internal clock monitor. These things shouldn't even need to be mentioned in the year 2016 and they are standard on pretty much every modern microcontroller.
If you have a safety and/or automotive-oriented MCU, it will have certain watchdog features, such as a given time window, inside which you need to refresh the watchdog. This is preferred if you have a mission-critical real-time system.
In general, use a MCU suitable for these kind of systems, and not some generic mainstream fluff you received in a packet of corn flakes. Almost every MCU manufacturer nowadays have specialized MCUs designed for safety applications (TI, Freescale, Renesas, ST, Infineon etc etc). These have lots of built-in safety features, including lock-step cores: meaning that there are 2 CPU cores executing the same code, and they must agree with each other.
IMPORTANT: You must ensure the integrity of internal MCU registers. All control & status registers of hardware peripherals that are writeable may be located in RAM memory, and are therefore vulnerable.
To protect yourself against register corruptions, preferably pick a microcontroller with built-in "write-once" features of registers. In addition, you need to store default values of all hardware registers in NVM and copy-down those values to your registers at regular intervals. You can ensure the integrity of important variables in the same manner.
Note: always use defensive programming. Meaning that you have to setup all registers in the MCU and not just the ones used by the application. You don't want some random hardware peripheral to suddenly wake up.
There are all kinds of methods to check for errors in RAM or NVM: checksums, "walking patterns", software ECC etc etc. The best solution nowadays is to not use any of these, but to use a MCU with built-in ECC and similar checks. Because doing this in software is complex, and the error check in itself could therefore introduce bugs and unexpected problems.
Use redundancy. You could store both volatile and non-volatile memory in two identical "mirror" segments, that must always be equivalent. Each segment could have a CRC checksum attached.
Avoid using external memories outside the MCU.
Implement a default interrupt service routine / default exception handler for all possible interrupts/exceptions. Even the ones you are not using. The default routine should do nothing except shutting off its own interrupt source.
Understand and embrace the concept of defensive programming. This means that your program needs to handle all possible cases, even those that cannot occur in theory. Examples.
High quality mission-critical firmware detects as many errors as possible, and then handles or ignores them in a safe manner.
Never write programs that rely on poorly-specified behavior. It is likely that such behavior might change drastically with unexpected hardware changes caused by radiation or EMI. The best way to ensure that your program is free from such crap is to use a coding standard like MISRA, together with a static analyser tool. This will also help with defensive programming and with weeding out bugs (why would you not want to detect bugs in any kind of application?).
IMPORTANT: Don't implement any reliance of the default values of static storage duration variables. That is, don't trust the default contents of the .data or .bss. There could be any amount of time between the point of initialization to the point where the variable is actually used, there could have been plenty of time for the RAM to get corrupted. Instead, write the program so that all such variables are set from NVM in run-time, just before the time when such a variable is used for the first time.
In practice this means that if a variable is declared at file scope or as static, you should never use = to initialize it (or you could, but it is pointless, because you cannot rely on the value anyhow). Always set it in run-time, just before use. If it is possible to repeatedly update such variables from NVM, then do so.
Similarly in C++, don't rely on constructors for static storage duration variables. Have the constructor(s) call a public "set-up" routine, which you can also call later on in run-time, straight from the caller application.
If possible, remove the "copy-down" start-up code that initializes .data and .bss (and calls C++ constructors) entirely, so that you get linker errors if you write code relying on such. Many compilers have the option to skip this, usually called "minimal/fast start-up" or similar.
This means that any external libraries have to be checked so that they don't contain any such reliance.
Implement and define a safe state for the program, to where you will revert in case of critical errors.
Implementing an error report/error log system is always helpful.
It may be possible to use C to write programs that behave robustly in such environments, but only if most forms of compiler optimization are disabled. Optimizing compilers are designed to replace many seemingly-redundant coding patterns with "more efficient" ones, and may have no clue that the reason the programmer is testing x==42 when the compiler knows there's no way x could possibly hold anything else is because the programmer wants to prevent the execution of certain code with x holding some other value--even in cases where the only way it could hold that value would be if the system received some kind of electrical glitch.
Declaring variables as volatile is often helpful, but may not be a panacea.
Of particular importance, note that safe coding often requires that dangerous
operations have hardware interlocks that require multiple steps to activate,
and that code be written using the pattern:
... code that checks system state
if (system_state_favors_activation)
{
prepare_for_activation();
... code that checks system state again
if (system_state_is_valid)
{
if (system_state_favors_activation)
trigger_activation();
}
else
perform_safety_shutdown_and_restart();
}
cancel_preparations();
If a compiler translates the code in relatively literal fashion, and if all
the checks for system state are repeated after the prepare_for_activation(),
the system may be robust against almost any plausible single glitch event,
even those which would arbitrarily corrupt the program counter and stack. If
a glitch occurs just after a call to prepare_for_activation(), that would imply
that activation would have been appropriate (since there's no other reason
prepare_for_activation() would have been called before the glitch). If the
glitch causes code to reach prepare_for_activation() inappropriately, but there
are no subsequent glitch events, there would be no way for code to subsequently
reach trigger_activation() without having passed through the validation check or calling cancel_preparations first [if the stack glitches, execution might proceed to a spot just before trigger_activation() after the context that called prepare_for_activation() returns, but the call to cancel_preparations() would have occurred between the calls to prepare_for_activation() and trigger_activation(), thus rendering the latter call harmless.
Such code may be safe in traditional C, but not with modern C compilers. Such compilers can be very dangerous in that sort of environment because aggressive they strive to only include code which will be relevant in situations that could come about via some well-defined mechanism and whose resulting consequences would also be well defined. Code whose purpose would be to detect and clean up after failures may, in some cases, end up making things worse. If the compiler determines that the attempted recovery would in some cases invoke undefined behavior, it may infer that the conditions that would necessitate such recovery in such cases cannot possibly occur, thus eliminating the code that would have checked for them.
This is an extremely broad subject. Basically, you can't really recover from memory corruption, but you can at least try to fail promptly. Here are a few techniques you could use:
checksum constant data. If you have any configuration data which stays constant for a long time (including hardware registers you have configured), compute its checksum on initialization and verify it periodically. When you see a mismatch, it's time to re-initialize or reset.
store variables with redundancy. If you have an important variable x, write its value in x1, x2 and x3 and read it as (x1 == x2) ? x2 : x3.
implement program flow monitoring. XOR a global flag with a unique value in important functions/branches called from the main loop. Running the program in a radiation-free environment with near-100% test coverage should give you the list of acceptable values of the flag at the end of the cycle. Reset if you see deviations.
monitor the stack pointer. In the beginning of the main loop, compare the stack pointer with its expected value. Reset on deviation.
What could help you is a watchdog. Watchdogs were used extensively in industrial computing in the 1980s. Hardware failures were much more common then - another answer also refers to that period.
A watchdog is a combined hardware/software feature. The hardware is a simple counter that counts down from a number (say 1023) to zero. TTL or other logic could be used.
The software has been designed as such that one routine monitors the correct operation of all essential systems. If this routine completes correctly = finds the computer running fine, it sets the counter back to 1023.
The overall design is so that under normal circumstances, the software prevents that the hardware counter will reach zero. In case the counter reaches zero, the hardware of the counter performs its one-and-only task and resets the entire system. From a counter perspective, zero equals 1024 and the counter continues counting down again.
This watchdog ensures that the attached computer is restarted in a many, many cases of failure. I must admit that I'm not familiar with hardware that is able to perform such a function on today's computers. Interfaces to external hardware are now a lot more complex than they used to be.
An inherent disadvantage of the watchdog is that the system is not available from the time it fails until the watchdog counter reaches zero + reboot time. While that time is generally much shorter than any external or human intervention, the supported equipment will need to be able to proceed without computer control for that timeframe.
This answer assumes you are concerned with having a system that works correctly, over and above having a system that is minimum cost or fast; most people playing with radioactive things value correctness / safety over speed / cost
Several people have suggested hardware changes you can make (fine - there's lots of good stuff here in answers already and I don't intend repeating all of it), and others have suggested redundancy (great in principle), but I don't think anyone has suggested how that redundancy might work in practice. How do you fail over? How do you know when something has 'gone wrong'? Many technologies work on the basis everything will work, and failure is thus a tricky thing to deal with. However, some distributed computing technologies designed for scale expect failure (after all with enough scale, failure of one node of many is inevitable with any MTBF for a single node); you can harness this for your environment.
Here are some ideas:
Ensure that your entire hardware is replicated n times (where n is greater than 2, and preferably odd), and that each hardware element can communicate with each other hardware element. Ethernet is one obvious way to do that, but there are many other far simpler routes that would give better protection (e.g. CAN). Minimise common components (even power supplies). This may mean sampling ADC inputs in multiple places for instance.
Ensure your application state is in a single place, e.g. in a finite state machine. This can be entirely RAM based, though does not preclude stable storage. It will thus be stored in several place.
Adopt a quorum protocol for changes of state. See RAFT for example. As you are working in C++, there are well known libraries for this. Changes to the FSM would only get made when a majority of nodes agree. Use a known good library for the protocol stack and the quorum protocol rather than rolling one yourself, or all your good work on redundancy will be wasted when the quorum protocol hangs up.
Ensure you checksum (e.g. CRC/SHA) your FSM, and store the CRC/SHA in the FSM itself (as well as transmitting in the message, and checksumming the messages themselves). Get the nodes to check their FSM regularly against these checksum, checksum incoming messages, and check their checksum matches the checksum of the quorum.
Build as many other internal checks into your system as possible, making nodes that detect their own failure reboot (this is better than carrying on half working provided you have enough nodes). Attempt to let them cleanly remove themselves from the quorum during rebooting in case they don't come up again. On reboot have them checksum the software image (and anything else they load) and do a full RAM test before reintroducing themselves to the quorum.
Use hardware to support you, but do so carefully. You can get ECC RAM, for instance, and regularly read/write through it to correct ECC errors (and panic if the error is uncorrectable). However (from memory) static RAM is far more tolerant of ionizing radiation than DRAM is in the first place, so it may be better to use static DRAM instead. See the first point under 'things I would not do' as well.
Let's say you have an 1% chance of failure of any given node within one day, and let's pretend you can make failures entirely independent. With 5 nodes, you'll need three to fail within one day, which is a .00001% chance. With more, well, you get the idea.
Things I would not do:
Underestimate the value of not having the problem to start off with. Unless weight is a concern, a large block of metal around your device is going to be a far cheaper and more reliable solution than a team of programmers can come up with. Ditto optical coupling of inputs of EMI is an issue, etc. Whatever, attempt when sourcing your components to source those rated best against ionizing radiation.
Roll your own algorithms. People have done this stuff before. Use their work. Fault tolerance and distributed algorithms are hard. Use other people's work where possible.
Use complicated compiler settings in the naive hope you detect more failures. If you are lucky, you may detect more failures. More likely, you will use a code-path within the compiler which has been less tested, particularly if you rolled it yourself.
Use techniques which are untested in your environment. Most people writing high availability software have to simulate failure modes to check their HA works correctly, and miss many failure modes as a result. You are in the 'fortunate' position of having frequent failures on demand. So test each technique, and ensure its application actual improves MTBF by an amount that exceeds the complexity to introduce it (with complexity comes bugs). Especially apply this to my advice re quorum algorithms etc.
Since you specifically ask for software solutions, and you are using C++, why not use operator overloading to make your own, safe datatypes? For example:
Instead of using uint32_t (and double, int64_t etc), make your own SAFE_uint32_t which contains a multiple (minimum of 3) of uint32_t. Overload all of the operations you want (* + - / << >> = == != etc) to perform, and make the overloaded operations perform independently on each internal value, ie don't do it once and copy the result. Both before and after, check that all of the internal values match. If values don't match, you can update the wrong one to the value with the most common one. If there is no most-common value, you can safely notify that there is an error.
This way it doesn't matter if corruption occurs in the ALU, registers, RAM, or on a bus, you will still have multiple attempts and a very good chance of catching errors. Note however though that this only works for the variables you can replace - your stack pointer for example will still be susceptible.
A side story: I ran into a similar issue, also on an old ARM chip. It turned out to be a toolchain which used an old version of GCC that, together with the specific chip we used, triggered a bug in certain edge cases that would (sometimes) corrupt values being passed into functions. Make sure your device doesn't have any problems before blaming it on radio-activity, and yes, sometimes it is a compiler bug =)
Disclaimer: I'm not a radioactivity professional nor worked for this kind of application. But I worked on soft errors and redundancy for long term archival of critical data, which is somewhat linked (same problem, different goals).
The main problem with radioactivity in my opinion is that radioactivity can switch bits, thus radioactivity can/will tamper any digital memory. These errors are usually called soft errors, bit rot, etc.
The question is then: how to compute reliably when your memory is unreliable?
To significantly reduce the rate of soft errors (at the expense of computational overhead since it will mostly be software-based solutions), you can either:
rely on the good old redundancy scheme, and more specifically the more efficient error correcting codes (same purpose, but cleverer algorithms so that you can recover more bits with less redundancy). This is sometimes (wrongly) also called checksumming. With this kind of solution, you will have to store the full state of your program at any moment in a master variable/class (or a struct?), compute an ECC, and check that the ECC is correct before doing anything, and if not, repair the fields. This solution however does not guarantee that your software can work (simply that it will work correctly when it can, or stops working if not, because ECC can tell you if something is wrong, and in this case you can stop your software so that you don't get fake results).
or you can use resilient algorithmic data structures, which guarantee, up to a some bound, that your program will still give correct results even in the presence of soft errors. These algorithms can be seen as a mix of common algorithmic structures with ECC schemes natively mixed in, but this is much more resilient than that, because the resiliency scheme is tightly bounded to the structure, so that you don't need to encode additional procedures to check the ECC, and usually they are a lot faster. These structures provide a way to ensure that your program will work under any condition, up to the theoretical bound of soft errors. You can also mix these resilient structures with the redundancy/ECC scheme for additional security (or encode your most important data structures as resilient, and the rest, the expendable data that you can recompute from the main data structures, as normal data structures with a bit of ECC or a parity check which is very fast to compute).
If you are interested in resilient data structures (which is a recent, but exciting, new field in algorithmics and redundancy engineering), I advise you to read the following documents:
Resilient algorithms data structures intro by Giuseppe F.Italiano, Universita di Roma "Tor Vergata"
Christiano, P., Demaine, E. D., & Kishore, S. (2011). Lossless fault-tolerant data structures with additive overhead. In Algorithms and Data Structures (pp. 243-254). Springer Berlin Heidelberg.
Ferraro-Petrillo, U., Grandoni, F., & Italiano, G. F. (2013). Data structures resilient to memory faults: an experimental study of dictionaries. Journal of Experimental Algorithmics (JEA), 18, 1-6.
Italiano, G. F. (2010). Resilient algorithms and data structures. In Algorithms and Complexity (pp. 13-24). Springer Berlin Heidelberg.
If you are interested in knowing more about the field of resilient data structures, you can checkout the works of Giuseppe F. Italiano (and work your way through the refs) and the Faulty-RAM model (introduced in Finocchi et al. 2005; Finocchi and Italiano 2008).
/EDIT: I illustrated the prevention/recovery from soft-errors mainly for RAM memory and data storage, but I didn't talk about computation (CPU) errors. Other answers already pointed at using atomic transactions like in databases, so I will propose another, simpler scheme: redundancy and majority vote.
The idea is that you simply do x times the same computation for each computation you need to do, and store the result in x different variables (with x >= 3). You can then compare your x variables:
if they all agree, then there's no computation error at all.
if they disagree, then you can use a majority vote to get the correct value, and since this means the computation was partially corrupted, you can also trigger a system/program state scan to check that the rest is ok.
if the majority vote cannot determine a winner (all x values are different), then it's a perfect signal for you to trigger the failsafe procedure (reboot, raise an alert to user, etc.).
This redundancy scheme is very fast compared to ECC (practically O(1)) and it provides you with a clear signal when you need to failsafe. The majority vote is also (almost) guaranteed to never produce corrupted output and also to recover from minor computation errors, because the probability that x computations give the same output is infinitesimal (because there is a huge amount of possible outputs, it's almost impossible to randomly get 3 times the same, even less chances if x > 3).
So with majority vote you are safe from corrupted output, and with redundancy x == 3, you can recover 1 error (with x == 4 it will be 2 errors recoverable, etc. -- the exact equation is nb_error_recoverable == (x-2) where x is the number of calculation repetitions because you need at least 2 agreeing calculations to recover using the majority vote).
The drawback is that you need to compute x times instead of once, so you have an additional computation cost, but's linear complexity so asymptotically you don't lose much for the benefits you gain. A fast way to do a majority vote is to compute the mode on an array, but you can also use a median filter.
Also, if you want to make extra sure the calculations are conducted correctly, if you can make your own hardware you can construct your device with x CPUs, and wire the system so that calculations are automatically duplicated across the x CPUs with a majority vote done mechanically at the end (using AND/OR gates for example). This is often implemented in airplanes and mission-critical devices (see triple modular redundancy). This way, you would not have any computational overhead (since the additional calculations will be done in parallel), and you have another layer of protection from soft errors (since the calculation duplication and majority vote will be managed directly by the hardware and not by software -- which can more easily get corrupted since a program is simply bits stored in memory...).
One point no-one seems to have mentioned. You say you're developing in GCC and cross-compiling onto ARM. How do you know that you don't have code which makes assumptions about free RAM, integer size, pointer size, how long it takes to do a certain operation, how long the system will run for continuously, or various stuff like that? This is a very common problem.
The answer is usually automated unit testing. Write test harnesses which exercise the code on the development system, then run the same test harnesses on the target system. Look for differences!
Also check for errata on your embedded device. You may find there's something about "don't do this because it'll crash, so enable that compiler option and the compiler will work around it".
In short, your most likely source of crashes is bugs in your code. Until you've made pretty damn sure this isn't the case, don't worry (yet) about more esoteric failure modes.
You want 3+ slave machines with a master outside the radiation environment. All I/O passes through the master which contains a vote and/or retry mechanism. The slaves must have a hardware watchdog each and the call to bump them should be surrounded by CRCs or the like to reduce the probability of involuntary bumping. Bumping should be controlled by the master, so lost connection with master equals reboot within a few seconds.
One advantage of this solution is that you can use the same API to the master as to the slaves, so redundancy becomes a transparent feature.
Edit: From the comments I feel the need to clarify the "CRC idea." The possibilty of the slave bumping it's own watchdog is close to zero if you surround the bump with CRC or digest checks on random data from the master. That random data is only sent from master when the slave under scrutiny is aligned with the others. The random data and CRC/digest are immediately cleared after each bump. The master-slave bump frequency should be more than double the watchdog timeout. The data sent from the master is uniquely generated every time.
How about running many instances of your application. If crashes are due to random memory bit changes, chances are some of your app instances will make it through and produce accurate results. It's probably quite easy (for someone with statistical background) to calculate how many instances do you need given bit flop probability to achieve as tiny overall error as you wish.
What you ask is quite complex topic - not easily answerable. Other answers are ok, but they covered just a small part of all the things you need to do.
As seen in comments, it is not possible to fix hardware problems 100%, however it is possible with high probabily to reduce or catch them using various techniques.
If I was you, I would create the software of the highest Safety integrity level level (SIL-4). Get the IEC 61513 document (for the nuclear industry) and follow it.
Someone mentioned using slower chips to prevent ions from flipping bits as easily. In a similar fashion perhaps use a specialized cpu/ram that actually uses multiple bits to store a single bit. Thus providing a hardware fault tolerance because it would be very unlikely that all of the bits would get flipped. So 1 = 1111 but would need to get hit 4 times to actually flipped. (4 might be a bad number since if 2 bits get flipped its already ambiguous). So if you go with 8, you get 8 times less ram and some fraction slower access time but a much more reliable data representation. You could probably do this both on the software level with a specialized compiler(allocate x amount more space for everything) or language implementation (write wrappers for data structures that allocate things this way). Or specialized hardware that has the same logical structure but does this in the firmware.
Perhaps it would help to know does it mean for the hardware to be "designed for this environment". How does it correct and/or indicates the presence of SEU errors ?
At one space exploration related project, we had a custom MCU, which would raise an exception/interrupt on SEU errors, but with some delay, i.e. some cycles may pass/instructions be executed after the one insn which caused the SEU exception.
Particularly vulnerable was the data cache, so a handler would invalidate the offending cache line and restart the program. Only that, due to the imprecise nature of the exception, the sequence of insns headed by the exception raising insn may not be restartable.
We identified the hazardous (not restartable) sequences (like lw $3, 0x0($2), followed by an insn, which modifies $2 and is not data-dependent on $3), and I made modifications to GCC, so such sequences do not occur (e.g. as a last resort, separating the two insns by a nop).
Just something to consider ...
If your hardware fails then you can use mechanical storage to recover it. If your code base is small and have some physical space then you can use a mechanical data store.
There will be a surface of material which will not be affected by radiation. Multiple gears will be there. A mechanical reader will run on all the gears and will be flexible to move up and down. Down means it is 0 and up means it is 1. From 0 and 1 you can generate your code base.
Use a cyclic scheduler. This gives you the ability to add regular maintenance times to check the correctness of critical data. The problem most often encountered is corruption of the stack. If your software is cyclical you can reinitialize the stack between cycles. Do not reuse the stacks for interrupt calls, setup a separate stack of each important interrupt call.
Similar to the Watchdog concept is deadline timers. Start a hardware timer before calling a function. If the function does not return before the deadline timer interrupts then reload the stack and try again. If it still fails after 3/5 tries you need reload from ROM.
Split your software into parts and isolate these parts to use separate memory areas and execution times (Especially in a control environment). Example: signal acquisition, prepossessing data, main algorithm and result implementation/transmission. This means a failure in one part will not cause failures through the rest of the program. So while we are repairing the signal acquisition the rest of tasks continues on stale data.
Everything needs CRCs. If you execute out of RAM even your .text needs a CRC. Check the CRCs regularly if you using a cyclical scheduler. Some compilers (not GCC) can generate CRCs for each section and some processors have dedicated hardware to do CRC calculations, but I guess that would fall out side of the scope of your question. Checking CRCs also prompts the ECC controller on the memory to repair single bit errors before it becomes a problem.
Use watchdogs for bootup no just once operational. You need hardware help if your bootup ran into trouble.
Firstly, design your application around failure. Ensure that as part of normal flow operation, it expects to reset (depending on your application and the type of failure either soft or hard). This is hard to get perfect: critical operations that require some degree of transactionality may need to be checked and tweaked at an assembly level so that an interruption at a key point cannot result in inconsistent external commands.
Fail fast as soon as any unrecoverable memory corruption or control flow deviation is detected. Log failures if possible.
Secondly, where possible, correct corruption and continue. This means checksumming and fixing constant tables (and program code if you can) often; perhaps before each major operation or on a timed interrupt, and storing variables in structures that autocorrect (again before each major op or on a timed interrupt take a majority vote from 3 and correct if is a single deviation). Log corrections if possible.
Thirdly, test failure. Set up a repeatable test environment that flips bits in memory psuedo-randomly. This will allow you to replicate corruption situations and help design your application around them.
Given supercat's comments, the tendencies of modern compilers, and other things, I'd be tempted to go back to the ancient days and write the whole code in assembly and static memory allocations everywhere. For this kind of utter reliability I think assembly no longer incurs a large percentage difference of the cost.
Here are huge amount of replies, but I'll try to sum up my ideas about this.
Something crashes or does not work correctly could be result of your own mistakes - then it should be easily to fix when you locate the problem. But there is also possibility of hardware failures - and that's difficult if not impossible to fix in overall.
I would recommend first to try to catch the problematic situation by logging (stack, registers, function calls) - either by logging them somewhere into file, or transmitting them somehow directly ("oh no - I'm crashing").
Recovery from such error situation is either reboot (if software is still alive and kicking) or hardware reset (e.g. hw watchdogs). Easier to start from first one.
If problem is hardware related - then logging should help you to identify in which function call problem occurs and that can give you inside knowledge of what is not working and where.
Also if code is relatively complex - it makes sense to "divide and conquer" it - meaning you remove / disable some function calls where you suspect problem is - typically disabling half of code and enabling another half - you can get "does work" / "does not work" kind of decision after which you can focus into another half of code. (Where problem is)
If problem occurs after some time - then stack overflow can be suspected - then it's better to monitor stack point registers - if they constantly grows.
And if you manage to fully minimize your code until "hello world" kind of application - and it's still failing randomly - then hardware problems are expected - and there needs to be "hardware upgrade" - meaning invent such cpu / ram / ... -hardware combination which would tolerate radiation better.
Most important thing is probably how you get your logs back if machine fully stopped / resetted / does not work - probably first thing bootstap should do - is a head back home if problematic situation is entcovered.
If it's possible in your environment also to transmit a signal and receive response - you could try out to construct some sort of online remote debugging environment, but then you must have at least of communication media working and some processor/ some ram in working state. And by remote debugging I mean either GDB / gdb stub kind of approach or your own implementation of what you need to get back from your application (e.g. download log files, download call stack, download ram, restart)
I've really read a lot of great answers!
Here is my 2 cent: build a statistical model of the memory/register abnormality, by writing a software to check the memory or to perform frequent register comparisons. Further, create an emulator, in the style of a virtual machine where you can experiment with the issue. I guess if you vary junction size, clock frequency, vendor, casing, etc would observe a different behavior.
Even our desktop PC memory has a certain rate of failure, which however doesn't impair the day to day work.

using getenv with respect to security

If I use getenv() to disable some verifications of my program (for instance license checking) will a hacker be able to discover easily the concerned environment variable (using strace or other ?)
Exemple of code:
if (! getenv("my_secret_env_variable")) checkLicense();
(If, on the other hand, I checked the presence of a specific file, the hacker would see it immediately with strace)
Let me add to the existing answers to give you a bit of a broader view about software protection.
Hackers won't just use strace, they'll use whatever tools they have in their tool chest but in order of increasing complexity, perhaps merely starting with something as simple as strings in most cases. Most hackers I know are inherently lazy and will therefore take the path of least resistance. (NB: by hacker I mean a technically very skilled person, not a cracker - the latter often has the same skill set, but a different set of ethics).
Generally speaking from the perspective of the reverse engineer, just about anything can be "cracked" or worked around. The question is how much time and/or determination the attacker has. Consider that some student may do this just for giggles, while some "release groups" do this for fame within their "scene".
Let's consider hardware dongles for example. Most software authors/companies think that they somehow magically "buy" security when licensing some dongle. However, if they aren't careful with the implementation of the system it is as simple to work around as your attempt. Even when they are careful enough, it is often still possible to emulate a dongle although it will require some skill to extract the information on the dongle. Some dongles (I will not conceal that fact from you) are therefore "smart", meaning they contain a CPU or even a full-fledged embedded system. If vital parts of a software product are executed on the dongle and all that enters the dongle is the input and all that leaves the dongle is the output, that makes for a pretty good protection. However, it will equally annoy honest customers and attackers for the most part.
Or let's consider encryption as another example. Many developers don't seem to grasp the concept of a public and a secret key and think that "hiding" the secret key inside the code makes it somehow safer. Well, it doesn't. The code contains the algorithm and the secret key now, how convenient is that for the attacker?
The general problem in most of these cases is that on one hand you trust the users (because you sell to them), but on the other hand you don't trust them (because you try to protect your software somehow). When you look at it this way you can see how futile it actually is. Most of the time you will disgruntle the honest customers, while only delaying the attacker a little (software protection is binary: either it gives protection or it doesn't, i.e. it's already cracked).
Consider instead the path the makers of IDA Pro took. They watermark all their binaries before the user gets them. Then, in case those binaries get leaked, legal measures can be taken. And even without taking legal measures into account they can shame (and have shamed) those that leaked their product publicly. Also, if you are responsible for a leak you won't be sold any upgrades to the software and the makers of IDA will not do business with your employer. That's quite an incentive to keep your copy of IDA safe. Now, I get it, IDA is somewhat of a niche product, but still the approach is fundamentally different and doesn't have the same issues as the conventional attempts at protecting software.
Another alternative is of course to offer a service rather than a software. So you could give the user a token that the software sends to your server. The server then offers an update (or whatever the service) based on decoding the token (which we assume to be an encrypted message) and checking validity. In this case the user would only receive the token but never the secret key to decode it, which your server on the other hand would have to validate the token. Call it product key or whatever, there are dozens of ways one can imagine. The point is that you don't end up in that contradiction of trusting and mistrusting the user at the same time. You only mistrust the user and can for example blacklist her token if that has been abused.
Yes. Any hardcoded string is trivially easy to discover inside of a compiled binary. The library call will also be easy to see. It's also possible to change the string inside of the binary to something else.
We also can LD_PRELOAD the getenv function to display the parameter receive
the hacker would see it immediately with strace - maybe you should take a look at ltrace as well?
While you might not be able to hide the variable name, why not require a value? In particular you could use an integer for a valid value (atoi) since they are a lot harder to spot in code, or even a combination of ints and single chars. However remember that the environment block is an easy part of memory to find, especially in a core dump.
Yes - Easy. They just use strings to find out what to try.

Getting into Embedded [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 9 years ago.
I'm trying to familiarize myself with the embedded field, but also have limited resources in terms of time and equipment to buy.
What's a good language to wrap my head around embedded, without investing too much time leaning an embedded-specific language? I'm most familiar with PHP, Java, Actionscript, but unfortunately know very little C. I remember reading somewhere that someone used PERL to program embedded systems, but not sure if that's really possible.
Can learning be done without needing to buy chips, etc. via simulators or such?
Can someone recommend a simplified roadmap to show how one would get sarted? I'm a little unsure where to even start.
You need to know C (but every programmer needs to know C !)
Most of these platforms have a simulator/emualtor, but since the point is to learn real applications and real problems ( which are all to do with real world timing issues) then you want a real board.
You probably also want an oscilloscope (a very cheap n'th hand slow analogue scope will do) and have some idea how to use it.
Easiest way in is probably Arduino, perhaps more professional but a little harder is launchpad MSP430
There are a few embedded programming lessons that carry over from one platform and style to another, but it is really a broad field. Different processors can require very different tactics, and different applications can dictate both different firmware design tactics and different microcontrollers. Here's some stuff to get you started....
msp430
Texas Instruments has several very inexpensive USB development kits which they call EZ430 and are based on their MSP430 family of micro-controllers. The simplest one has an msp430 f2013, which has 2K of flash program space, 3x128 bytes of usable user flash (another 128 byte page exists, but it's special), 128 bytes of RAM (yes, 128 bytes but it's enough for lots of things), and 16 CPU registers (some of these are special purpose like the Stack Pointer, Instruction Pointer, Status Register, and maybe one or two more). MSP430s also have several memory mapped special function registers which are used for configuring and controlling the built in peripherals. MSP430s are von Newman processors, so everything lives within one address space. These cost about $20us for both the programmer and a removable tab (pc board) containing the msp430 f2013. For about $10us you can get 3 replacement tabs with msp430 2012, which is pin compatible with the 2013 (mostly) and has a few different peripherals. These tabs have an LED, a button, and several large vias (holes in the pc board) which are connected to the pin of the processor. These vias are easy to solder wires into even if you have never soldered before -- due to capillary action the vias just suck the molten solder up and while it's hot you can just jab the end of your wire in there.
They also have a couple more similar kits with 802.15.4 radios. Even if you aren't interested in the radio you may still be interested in these because their programmer also has a UART pulled over from the removable tab and are compatible with the tabs used on the other kits mentioned above. These kits also contain at least one extra programmable board and a battery pack for it. (one of these kits may contain more, but I don't have mine with me right now, and not going to look it up).
They also have a kit that has a programmable watch as the target platform. I've never had one of these, but they have a display, accelerometers, and several other cool things, but this may overwhelm you for your first project. I'd suggest one of the previous kits to get you started with MSP430s.
You can get free C compilers and development environments for MSP430s in the form of IAR's Embedded Workbench kickstart (4 kb program space limited ) IDE, Code Composer Studio (also limited program size, but higher limit, I think), and gcc/gdb for the MSP430. IAR's kickstart is pretty easy to get started with quickly, though it's not perfect. You may find that you have to shut it down, unplug your USB EZ430, restart IAR, and plug back in to get it going again. Or maybe some different order will work better for you.
TI also provides many examples in badly named files (all of their downloadable files go out of their way to be badly named). Be warned -- similar MSP430s may have different device control register interfaces for similar peripherals, which can be confusing. Make sure that any document or example you are reading really does apply to the microcontroller you are using.
other small systems
There are many many other processors families and kits that you can go with, and you should probably at least know a little bit about them.
AVR -- Atmel's 8/16 bit Harvard architecture. Harvard refers to separate address spaces for code and working memory. It has 32 8 bit registers, some of which may be used in pairs as 16 bit registers. It's a very popular and pretty cool processor. Some of the smallest ones only have registers with no extra RAM, which is scary. Atmel also has an AVR32 which isn't at all the same as the AVR. Unless you make use of an existing bootloader capable of loading your new code you will need to get a JTAG unit for these.
8051 -- This is old as the hills and a pain in the butt to use until you finally understand it. It is an 8/16 bit processor, with many more limits on how you go about doing 16 bit math and only has 1 pair of registers which can act as a pointer. It has 3 separate address spaces (stack, global memory, and code) and lots of odd (compared to other architectures) features. The low level stuff might not mean much to you if your are programming in C except that very simple C operations can turn into much more code than you thought they would. You don't want to start on one of thise, most likely.
propeller -- Parallax's very interesting multi-core processor which is very unlike other processors. It has several cores which act mostly independently and can be used to simulate peripherals or do more traditional computational tasks. I've never used one of these, though I'd like to. Just never had a task that seemed to fit it. They have their own high level language to program them as well as the processor's assembly language.
larger systems
After you get out of the 8/16/24 bit processors you start to blur the lines between embedded and desktop level programming, even if it is technically embedded.
AVR32 -- There are 2 main versions of these. One is a Harvard architecture and the other is von Newman. The von Newman version is essentially a better ARM than ARM, but it's not as popular as ARM. As near as I can tell it was designed with "run Linux" in mind, though not tied to it in any crazy way. You used to be able to get cheap development boards for these and code is often almost as easy to load as copying files from one PC to another, though you will probably make use of uboot and tftp to do some work. JTAG is only needed when you mess up the boot loader. I think all of these have support for native JAVA acceleration. www.AVR32.org
ARM -- The most popular embedded processor. There's many versions of these. Some don't have an MMU (memory management unit) and some do. There's too much to say about them. Some version have native JAVA acceleration, though I think that the ARM lords don't freely tell all of the details of how to use it, so you have to find a JVM which knows how to use it. Many vendors make them, including Atmel, Freescale, Intel, and many others.
MIPS -- A very RISC processor. The RISCiest.
There are many others.
Programming styles
I could write 3 books on this but the general rule is make things as simple as the application can let you. An exception to this is that if you can easily make use of an operating system you might want to make use of it if it simplifies your task.
The first thing you need to know when answering this question is "WHAT IS" an embedded system? A GENERAL definition would be a computer system which is dedicated to a single specific purpose. This doesn't limit the type of hardware you can use, as matter of fact "Embedded PCs" have been used for years. The QNX realtime OS has existed since the early 80s and been used in industrial PCs for embedded applications for years. I've personally used in control systems for steel mills XRAY thickness gages. On the other hand I currently use TI DSPs without any OS support and only using 256K of Ram. Another example would be the key fob for your car. Old ones used to use a PIC microcontroller from Microchip. (That's actually the company's name.)
Some people call the IPhone an embedded system, but due to the fact you can load applications to do just about anything I tend to say it's a palm top computer with phone capabilities. An OLD DUMB cell phone that is just a phone, not PDA is an embedded system. That's just a bit of philosophy.
As a general rule there are a handful of concepts you need to grasp for embedded systems programming, and most of them can be explored on a PC.
EDIT:
The REASON why C or C++ is recommended is C itself was designed to do systems programming. C++ maintains all it's advantages but adds capabilities for OOP programming. Some ASM maybe required in some systems. However a lot of chip vendors, such as TI, provide tools basically make it possible to do your entire system in C++.
:END EDIT
ALOT of simple embedded systems look more or less like this:
While(true) // LOOP FOREVER... There is no command prompt
{
// Typically you want I/O to occur on fixed "timebase."
wait(timerTick);
readDigitalIO(&dioStruct);
readAnalogIO(&aioStruct);
// Combine current system state with input values
// and do some useful calculations. (i.e. Analog input to temperature calc)
Process(dioStruct,aioStruct,&CurrentState);
// This can be a serial output/audio buzzer/leds/motor controller
// or Whatever the system REQUIREMENT call for.
driveOutputs(CurrentState);
// The watchdog timer resets your system if it gets stuck.
petWatchDogTimer();
}
There is nothing here that you can't do using the PC. (Well a PC that still has a parallel port anyway. Which is a more or less just a DIO port.) On a simple system without a os this might be all there is. On a RTOS based system you may have several task that all look somewhat simalar to this, but pass data back and forth between the tasks.
The interesting parts come when you have to interface to the hardware on you're own, the first job I had out of college was writing a device driver for a data acquisition board under QNX.
Basic concepts of dealing with hardware, or device drivers (Which you can experiement with by hacking Linux device drive code which is freely avaliable.), most hardware looks to the programmer like just another memory address. This is called "Memory mapped I/O." What does this mean? Lets use a serial port as an example:
// Serial port registers definition:
typedef struct
{
unsigned int control; // Control bits for the port.
unsigned int baudDiv; // Baud rate divider.
unsigned int status; // READ Status bits/ Write resets fifos;
char TXdata; // The head of the hardware TX fifo.
char RXdata; // The tail of the hardware RX filo.
} serRegs;
// Using the volatile keyword to indicate the hardware can change the value
// independantly from the software.
volatile serRegs *Ser1 = (serRegs *)0x8000; // Hardware exists at a specific location in memory.
volatile serRegs *Ser2 = (serRegs *)0x8010; // Hardware exists at a specific location in memory.
// Bits bits 15-12 enable interupts and select interupt vector,
// bits 11-8 enable,bits 7-4 parity,bits 3-0 stop bits.
Ser1->status = 1; // Reset fifos.
Ser1->baudDiv = CLOCKVALUE / 9600; // Set the baudrate 9600;
Ser1->control = 0x1801; // Enable, 8 data, no parity, 1 stop bit.
// Write out a "OK\r\n" message; (Normally this would be a loop.)
Ser1->Txdata = 'O'; // First byte in fifo Transmission starts.
Ser1->Txdata = 'K'; // Second byte in fifo still transmitting first byte
Ser1->Txdata = '\r'; // Third byte in fifo still transmitting first byte
Ser1->Txdata = '\n'; // Fouth byte in fifo still transmitting first byte
Normally you would have a function or an interrupt handler to handle TXing the data, but for example I wanted to point out that the hardware is working while the software keeps going. Basically hardware works like, I write a value to an address and "STUFF" happens independantly of the software. This is perhaps one of the key concepts for embedded programming, how to make the computer effect a change in the real world.
EDIT:
If you actually want to get a cheap board, the current trend from Micro developers is to put a dev kit on a usb thumb stick. This page has info on several, ranging from 8 bits upto ARM architectures: http://dev.emcelettronica.com/microcontrollers-usb-stick-tool
The Cypress PSOC was one of the first to do this with the "FirstTouch Starter Kit." The PSOC is a very unique part in that it has a micro controller and "Configurable analog and digital blocks" that allow you to plop down a ADC, serial port, or digital I/O using a gui and automatically configures you're C app to use it. The PSOCs also are avaliable in DIP packages which makes them easy to use on a prototyper's breadboard.
Picture your embedded controller sitting in a switched-off circuit...
The Vcc power is applied and the reset circuit asserts reset signal.
Clocks have reached running speeds and voltages stabilized, so reset is de-asserted.
Now your controller sets its instruction pointer to the "reset vector," which is physical address 0xE0000000 on this particular chip. The controller fetches the instruction at that location.
Interrupts are disabled, and the first order of business is to initialize registers such as the stack pointer. On some chips, there are flags bits (e.g., x86 direction flag) which need to be cleared or set.
Once the registers and flag bits are set up correctly, it becomes possible for interrupt service routines to run. By now, we must have run code to about location 0xE0000072 when we get to the code which enables interrupts by first toggling some GPIO pins to the external interrupt controller, then enables the CPU interrupts mask.
At this point, the equivalent of "device drivers" are running in the form of interrupt service routines. Assuming the C environment has a library which matches the interfaces of these routines' data structures, by now our boot-loader code can jump to the main() function of some C object code.
In other words, the code which brought us from power-on to main(), and which handles the low-level I/O, is written in the assembler peculiar to the chip you choose. This means that if you want to be versatile at embedded programming, you must know how to implement assembly code starting at the reset vector.
The reality is that hobbyist embedded programming doesn't allow time for implementing all the ISRs and the boot-loader code. For this reason, many people use standard software frameworks available for specific chips. Others use custom-language chips such as the BASICstamp. The BASICstamp is an embedded chip which hosts a BASIC language interpreter on-board. The interpreter and all the ISRs are pre-written for you. The BASIC environment gives you the ability to control I/O pins, read voltages, everything you could do from assembly with an embedded controller, but a bit slower.
As for the language, C is probably the most important language to know. From Java you should be able to adapt, but just remember that a lot of high level Java will not be available to you. Loads of textbooks out there but I'd recommend the original C programming book by Kernighan and Ritchie http://en.wikipedia.org/wiki/The_C_Programming_Language_(book)
For a good introduction to embedded C you could try a book by Michael J Pont:
http://www.amazon.com/Embedded-C-Michael-J-Pont/dp/020179523X
As for the embedded side of things you could start with Microchip, the IDE is OK to develop in with a reasonable simulator, and the c compilers are free for the slightly limited student editions c18 and c30 compilers, the IDE installer will also ask if you want to install a 3rd party HI-TECH C compiler which you could use. As for the processor I'd recommend selecting a standard 18 series PIC such as the PIC18F4520.
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1406&dDocName=en019469&part=SW007002
Whatever the chip manufacturer, you have to get to know the datasheets. You don't have to learn it all at once but will need it to hand!
Embedded, like most programming, tends to revolve around:
1) initialising a resource, in this case rather than data being from a data store it is from computer registers. Just include the processor header file (.h) and it will allow you to access these as ports (usually bytes) or pins (bits). Also micro-processors come with useful resources on the chip such as timers, analogue to digital converters (ADCs) and serial communications systems (UARTs). Remember that the chip itself is a resource and needs initialising before anything else.
2) using the resource. C will allow you to make data as global as possible and everything can access everything at every time! Avoid this temptation and keep it modular like Java will have encouraged you to (though for speed you may need to be a little looser on these rules).
But they do have an extra weapon called interrupts which can be used to provide real-time behaviour. These can be thought of a bit like OnClick() events. Interrupts can be generated by external events (e.g. buttons or receiving a byte from another device) and internal (timers, transmissions completed, ADC conversions completed). Keep interrupt service routines (ISRs) short and sweet, use them to handle real-time events (e.g. take a byte received and store it in a buffer then raise a flag) but allow background code to deal with it (e.g. check a received byte flag, if set then read the byte received). And remember the all important volatile for variables used by ISR routines and background routines!
Anyway, read around, I recommend www.ganssle.com for advice in general.
Good luck!
The scope of embedded computing has grown very broad, so the answers somewhat depend on what kind of device you're aiming at. On one end, there are 8-bit controllers with only a few KB of memory, usually programmed entirely in assembly or C. On the other end, processors such as those in your router are fairly powerful (200 MHz and a few MB of RAM is not uncommon) and often run an OS like Linux, which means you can use pretty much any language, though C and Java are the most common.
It's best to buy a real chip and experiment. Most of the work involved is usually in getting to know a device and how to interface with it, so using a simulator kind of defeats the purpose.
What's a good language to wrap my head around embedded, without investing too much time leaning an embedded-specific language?
As everyone will suggest: C. Now depending on how deep are you going to dig into your platform of choice, you may also need some assembly, but don't be scared about that: typically you'll use just a little.
If you are learning C, my personal suggestion is: work as you would do in assembly; the programming language won't give you much abstractions, so think in terms of memory management. When you've learnt how to do it move up towards abstractions and live happy.
C++ is also popular on embedded platforms, but IMHO is difficult unless you know well how to program in C you can also understand what's under the hood of its abstraction.
When you feel confident with C/C++ you can start to mess with embedded operating systems. You'll notice that they can be totally different from your OS of choice (By example not all operating systems have a C standard library, processes and splitting between userspace and kernelspace).
You'll learn how to build a cross compiler, how to mess with linker scripts, the tricks of binary formats and a lot of cool stuff.
For the theoretical point of view there's a lot of stuff as well: if you study Computer Science you can get a master's degree in embedded systems.
Can learning be done without needing to buy chips, etc. via simulators or such?
Yes: many operating systems can be run on simulators like qemu.
Can someone recommend a simplified roadmap to show how one would get sarted? I'm a little unsure where to even start.
Try to get a simple operating system which can be run on emulators, hack it and follow your curiosity. Don't be scared of messing with knotty code.
1) Most of the time for most and usually the lower end embedded system, you need to know C.
And I will still recommend you to get a vanilla development board to get yourself familiar with the work flow and tricky part of working with embedded system like debugging and cross compiling. You will run into trouble if you only rely on emulator.
You can try out The Linux Stamp, it is not expensive and is good for beginner but you do need some prior knowledge on Linux.
2) For high end embedded system, a good example is Smartphone from HTC (CPU speed can reach 1Ghz)or some other Android phone it run fast and you can even code Java on it.
C and the assembly specific to your chip.
No, you really need a real chip. Simulators aren't the real thing. You need to be able to deal with keypress jitter, voltage funkyness, etc.
The Arduino is the current fad for embedded hobbyists. I'm not a big fan of Harvard architecture, personally. But you will find oodles of help out there for it. I use an XCore for my thesis work and I have found it super easy to program multicore stuff. I would suggest starting with an AVR32 and going from there.
As everyone else is saying, you need to know C.
Have a look at AVR butterfly for a cheap development board.
Smileymicros have a simple kit with dev board and book:
http://www.smileymicros.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=41
The soon to ship Raspberry Pi board looks like an incredibly cheap way to get into this field.
Yup, Arduino would be the way to go. Agreed.. Cheap (about $20 to start) and has great API to get started with high level functions. C is a must though, can't avoid it. But if you can program in other languages you'll be all good.
My recommendation is to start shopping at http://www.sparkfun.com lots of examples to work from and helpful hints of what devices to buy.

1k of Program Space, 64 bytes of RAM. Is 1 wire communication possible?

(If your lazy see bottom for TL;DR)
Hello, I am planning to build a new (prototype) project dealing with physical computing. Basically, I have wires. These wires all need to have their voltage read at the same time. More than a few hundred microseconds difference between the readings of each wire will completely screw it up. The Arduino takes about 114 microseconds. So the most I could read is 2 or 3 wires before the latency would skew the accuracy of the readings.
So my plan is to have an Arduino as the "master" of an array of ATTinys. The arduino is pretty cramped for space, but it's a massive playground compared to the tinys. An ATTiny13A has 1k of flash ROM(program space), 64 bytes of RAM, and 64 bytes of (not-durable and slow) EEPROM. (I'm choosing this for price as well as size)
The ATTinys in my system will not do much. Basically, all they will do is wait for a signal from the Master, and then read the voltage of 1 or 2 wires and store it in RAM(or possibly EEPROM if it's that cramped). And then send it to the Master using only 1 wire for data.(no room for more than that!).
So far then, all I should have to do is implement trivial voltage reading code (using built in ADC). But this communication bit I'm worried about. Do you think a communication protocol(using just 1 wire!) could even be implemented in such constraints?
TL;DR: In less than 1k of program space and 64 bytes of RAM(and 64 bytes of EEPROM) do you think it is possible to implement a 1 wire communication protocol? Would I need to drop to assembly to make it fit?
I know that currently my Arduino programs linking to the Wiring library are over 8k, so I'm a bit concerned.
Since you only need to send data (which is simpler than receiving) and you can select your own protocol, it should not be a problem to fit the code in the available memory space.
I once created software for an industrial control panel that contained 8x14 segment LCD display, some LEDs, some buttons, a serial (I2C) EEPROM, and serial interface to the host. A 4 bit processor was used. The device did not have any serial interface, so both the RS232C interface and I2C bus had to be implemented in software. On top of that, there was Modbus protocol (which among other things requires CRC calculations some exact timing), and the application program.
The device had some 128 x 4 bits of RAM and 1kW, 2kW, 3kW or 4kW of ROM (10 bits per word). The size of the final program was about 1100 words, so it did not quite fit in the smallest device. I used Assembler, of course.
However, instead of using multiple microcontrollers, you could consider using a hardware solution.
You could use a sample and hold circuit. For that, you need an array of analog switches and capacitors and perhaps op-amps. Just issue a trigger to latch all the voltages into the capacitors. Then you can use as much time as you need to read the voltages with your master processor.
Update: Forgot to mention that there are ready-made sample-and-hold amplifiers that need very little or no external components. This is probably the easiest solution.
1k of program space should be plenty, considering that your protocol only needs to be complicated enough to send a single integer when tickled. Look into Manchester Encoding.
You can probably get away with using a C compiler that targets this architecture, but you'll have to create your own runtime environment and not rely on the one supplied with the compiler. That's doable, but I'm not sure if the additional work to essentially create your own mini-OS outweighs the productivity benefit of using C over assembler.
I've done embedded programming in similar constraints. I used Borland Turbo C (it was a long time ago) in the tiny model and obtained code that was hardly bulkier than I could have done in assembler, with a fraction of the effort. What I'm saying is: It's quite feasible and sensible to use C as a high level assembler.
Just like me, though, you will be facing the problem of providing C with a (tiny) runtime environment. Ideally, you will only need to set up the stack and a few registers. Also, you won't have room for the C library, so you will need to program any needed functions yourself.
Yes, probably, though if you know your compiler very well you might be able to get away with c.
What you could do, is use a compiler to emit any standalone functions you need based on c code, then glue them together with a little of your own. (You'll certainly have to do the c runtime setup yourself - stacks etc.)
You may consider upgrading to the ATTiny25. It is a more capable 8-pin AVR that includes Atmel's Universal Serial Interface. It is capable of doing 1-wire serial comms in hardware, given only a few bytes of software.
Why wouldn't you just use sample-and-hold hardware, rather than a pile of microcontrollers?
I designed a master-slave system recently using an AT90USB646 master and ATtiny85 slaves. Obviously I had a lot more memory to work with on the slaves, but what I wanted to share with you is this:
With regard to your communication protocol, bear in mind that the uncalibrated internal oscillator on the ATtiny13 has an accuracy of +/- 10%. This means you won't be able to use, e.g., RS-232 communications.
I used a variant of the Dallas 1-Wire protocol in my system. Including full support for slave enumeration etc., the C source code compiles into 1626 bytes.
Edit: Whoops, didn't realize the question is so old. Hopefully this may still be of some help.

Resources