polling hardware button's state - embedded

I need to implement the following feature for my device running embedde linux on a 200mhz MIPS cpu:
1) if a reset button is pressed and held for less then a second - proceed with reboot
2) if a reset button is pressed and held for at least 3 sec. - restore the system's configuration with default values from NVRAM and then reboot.
I'm thinking of two ways:
1) a daemon that constantly polls the button's state with proper timings via GPIO ioctls
(likely too big overhead, lots of context switching ?)
2) simple char driver polling the button, measuring timings and reporting the state, for example, via /proc to user space where daemon or a shell script can check and do what's required.
And for both cases I have no idea how to measure the time :(
What would you suggest/recommend?

You have to implement those in hardware. The purpose of the "restore defaults from NVRAM" is to restore a so-called "bricked" device.
For example, what if an NVRAM seting is modified (cosmic ray?) such that the device cannot boot? In that case, your proposed button-polling daemon will never execute.
For the one-second held reboot, use an RC (resistor + capacitor) circuit to "debounce" the button press. Select an RC time constant which is appropriate for the one second delay. Use a comparator watching the RC voltage to signal the RESET pin on the MIPS cpu.
For the three-second press functionality (restore NVRAM defaults), you have to do something more complicated, probably.
One possibility is to put a tiny PIC microcontroller into the reset circuit, but only use a microcontroller with fuse (non-erasable) ROM, not NVRAM.
An easier possibility is to have a ROM containing defaults on the same circuit and bus as the NVRAM. A J/K flip-flop latch can become part of your reset circuitry. You'll also need a three-second-tuned RC circuit and comparator. On sub-three-second presses, the flip-flop should latch a 0 output and on three-second-plus presses, the 2nd RC circuit should trigger the comparator after 3 seconds and present a 1 to the J/K latch, which will toggle its output.
The flip-flop output Q will store the single bit telling your circuit whether this reset cycle was subsequent to a three-second push. If so, that output Q is driving the chip select to the NVRAM and Q* is driving the chip select to ROM. (I assume chip select is negative logic on both NVRAM and ROM chips.)
Then when your CPU boots, it will fetch the settings from either the NVRAM or the ROM, depending on the chip select line.
Your boot code can detect that it booted with ROM chip select, and can later reset the J/K flip-flop with a GPIO line. Then the CPU will be able to write good values back into the NVRAM. That unbricks the device, hopefully.
You want to use ROM that is not erasable or reusable. That kind of ROM is the most resistant to static electricity, power supply trouble, and radiation. Radiation is much more present than we generally realize, and the amount of cosmic ray flux is multiplied by taking a device onboard an airliner, for example.

I am not familiar with the MIPS processor and the GPIO/interrupt capabilities of the pin that you could be using but a possible methodology could be as follows.
Configure the input pin as an interrupt input.
When the interrupt fires disable the interrupt and start a short 100ms-ish timer
When the timer triggers check that the button is still pressed (for debounce). If it is not then re-enable the GPIO interrupt and restart, otherwise set the timer to re-trigger after the 3 second timeout.
When the timer triggers this time then if the button is not pressed then do your reboot otherwise reset the system configuration and reboot.
If the pin cannot provide an interrupt then step 1 will be a polling task to look at the input.
The time between the reset button being pressed and the full reset process being run will always be 3 seconds from a debounced button press. In a reset situation this may not be important particularly if as part of step 3 you make it apparent to the user that a reset sequence has started - blank the display for example.

If you want to do this in software, you need to put this in kernel (interrupt) code, rather than in a shell script or daemon. The better approach would be to put this in hardware.
In my experience, the likely reason for resetting the device will be bad user code which has locked or bricked the processor. If the issue is a corruption of memory due to RF energy or something of that nature, you may require hardware or an external (hardened) processor to reflash the device and fix the problem.
In the bad-user-code case, processor interrupts and kernel code should continue to run, while user code may be completely stalled. If you can poll the pin from an interrupt, you stand a much better chance of actually getting the reset you expect. Also, this enables you to do event-driven programming, rather than constantly polling the pin.
One other approach (not to the specs you listed, but a popular method for achieving the same goal) would be to have the startup routines check a GPIO line, and hold a button down when you want to re-initialize the device. On most embedded Linux devices which I've seen, the "Reset" button is wired to a dedicated reset pin on the microcontroller, and not to a GPIO pin. You may have to go with this route, unless you want to start cutting traces.

Related

Flags getting randomly set in RCC(Reset and Clock Control register) on Power On

I am working on MM32Spin05 MCU. After power on, all 6 flags in the RCC(Reset and Clock Control) register are getting set.
After a reset, the default value of this register should be 0X XC000000.
But I am observing it as 0X FC000000.
I am not doing anything with respect to the watchdog timers, or the low power module or the s/w reset.
I have a requirement, that, if a software reset is done, a certain page in the flash memory is to be cleared. But on boot up, the flag is set for reasons unknown to me and hence, the flash memory page is getting cleared.
I am actually doing a Power Reset. I am turning off and then turning on the power supply to the MCU. On boot-up, the Software Reset flag is set and hence, according to my code, it is triggering the flash memory page erase. The Flash memory page should be erased ONLY on a software reset, not a power reset. Immediately after the MCU boots up, I print the RCC_CSR Register value, and see that all 6 flags are set.
LPWRRSTF: Low power reset flag
WDGRSTF: Window watchdog reset flag
IWDGRSTF: Independent watchdog reset flag
SFTRSTF: Software reset flag
PORRSTF: POR/PDR reset flag
PINRSTF: PIN reset flag
I am confused, as to why, a power reset is causing the software reset flag to set?
I am stuck on this for more than a week and am fully clueless about it. Any help or suggestions would be highly welcome.
Thanks in Advance
As the manual says, the top 4 bits are "don't care" on power-on (or pin) reset, and they can have any value.
Only if none of PORRSTF and PINRSTF are set, the other bits are relevant.
Even then you need to read the manual carefully to understand the conditions of these bits. There might be more to do than a simple single-bit check.

TinyAVR 0-Series: Can I use pin-change sensing without entering interrupt handler?

I am evaluating the ATtiny806 running at 20MHz to build a cycle-accurate Intel 4004 microprocessor emulator. (I know it will be a bit too slow, but AVRs have a huge community.)
I need to synchronize to the external, two-phase non-overlapping clocks. These are not fast clocks (the original 4004 ran at 750kHz)
but if I spin-wait for every clock edge, I risk wasting most of my time budget.
The TinyAVR 0-series has a very nice pin-change interrupt facility that can be configured to trigger only on rising edges.
But, an interrupt routine round-trip is 8 cycles (3 in, 5 out).
My question is:
Can I leverage the pin-change sensing mechanism while never visiting an ISR?
(Other processor families let you poll for interruptible conditions without enabling interrupts from that peripheral). Can polling be done with a tight skip-on-bit/jump-back loop, followed by a set-bit instruction?
Straightforward way
You can always just poll on the level of the GPIO pin using the single cycle skip if bit set/clear instruction on the appropriate PORT register and bit.
But as you mention, polling does burn cycles so I'm not sure exactly what you want here - either a poll (that burns cycles but has low latency) or an interrupt (that has higher latency but allows processing to continue until the condition is true).
Note that if things get really tight and you are looking for, say, power savings by sleeping between clock signal transitions then you can do tricks like having an ISR that nevers returns (saving the IRET cycles) but that requires some careful coding probably with something like a state machine.
INTFLAG way
Alternately, if you want to use the internal pin state machine logic and you can live without interrupts, then you can use the INTFLAGS flags to check for the pin change configured in the ISC bits of the PINxCTRL register. As long as global interrupts are not enabled in SREG then you can spin poll on the appropriate INTFLAG bit to check/wait for the desired condition, and then write a 1 to that bit to clear the flag.
Note that if you want to make this fast, you will probably want to map the appropriate PORT to a VPORT since the VPORT registers are in I/O Memory. This lets you use SBIS to test the INTFLAG bit a single cycle and SBI to clear the bit in a single cycle (these instructions only work on IO memory and the normal PORT registers are not in IO Memory).
Finally one more complication, if you need to leave the interrupts on when doing this, it is probably possible by hacking the interrupt priority registers. You'd set the pin change to be on level 0, and then make sure the interrupts you care about are level 1 or higher, and then trick the interrupt controller into thinking that there is already a level 0 running so these interrupts do not actually fire. There are also other restrictions to this strategy so avoid it if at all possible.
Programmable logic way
If you want to get really esoteric, it is likely possible that you could route the input value of a pin to a configurable custom logic LUT in the chip and then route the output of that module to a bit that you test using a 1-cycle bit test (maybe an unused IO Pin). To do this, you'd feedback the output of the LUT back into one of its inputs and then use the LUT to create a strobe on the edge you are looking for. This is very complex, and also since the strobe has no acknowledgement that if the signal changes when you are not looking for it (in a spin check) then it will be lost and you will have to wait for the next edge (probably fatal in your application).

How to deep sleep an Attiny until an analog value of a photoresistor changes?

for a battery powered project I would like to put an Attiny85 into deep sleep mode immediately after program start and let it wake up only when a sensor value (in this case a photo resistor) changes. Unfortunately I could only find examples for interrupts by a button and not for photo resistors in the internet. Does anyone have an idea how I could implement it, or if it is impossible?
Turn out that this is probably a software question.
Probably to lowest power and simplest way to implement this would be to...
Connect the analog sensor value to any one of the analog input pins on the ATTINY.
Make sure you disable the digital buffer on that pin.
Set up the ADC to point to the pin and set other relevant values like precaller.
Set up a watchdog timer to fire a periodic interrupt.
Go into deep sleep and wait for the watchdog timer to fire.
Each time the watchdog fires...
Enable the the ADC.
Take a sample.
Jump to main code if the value has changed more than your threshold.
Disable ADC.
Go back to deep sleep.
How power efficient this will be really depends on how often the timer interrupt fires - the less often the better. If your application can live with only checking the sensor, say, once per second then I bet power usage will be single digits of microamps or less.
If you really need very low latency when that sensor values changes, then you could instead use the build in analog comparitor...
.. to generate an interrupt when the input voltage goes above or below a threshold value, but this will likely use much more power since just the analog comparitor itself uses ~30ua while on, and you will also need to generate the voltage that you are comparing to either with the internal 1.1 voltage reference or an external resistor bridge or buffer capacitor.

How would an ISR know what pin cause the interrupt?

Interrupts can be enabled for a specific pin(s) on a digital I/O port, correct? How would the ISR determine which pin caused the interrupt?
Because the vector table has only one slot for the Port1 ISR. So the same ISR function gets called no matter which input pin on Port1 needs attention unless I'm wrong...
As other people have suggested in comments this can be MCU dependent, but for ARM(The core behind MSP432) generally the answer is it doesnt know, it looks for it.
ARM has a vectored interrupt system, which means that every source has its own vector of interrupt, so CPU can easily find out which source is triggering thr interrupt. so far so good.
but then it happens that a device can trigger multiple interrupts, like GPIO as you said, in this case, CPU knows that which port has triggered interrupt so fires it's ISR but then it is ISR responsibility to poll device registers to figure out exact interrupt source, there are many of this peripherals with multiple interrupt, timers, DMAs just to name a few.
This is exactly why normally peripherals have an interrupt enable bit, that lets them trigger interrupts, but they also have bit masks that controls what exactly can trigger that interrupt internally,
Also have a look at this link for an in action example, specially at their ISR that does exactly the same as described above
In a typical MCU, there are hundreds, or at a stretch even thousands of potential interrupt sources. Depending on the application, only some will be important, and even fewer will be genuinely timing critical.
For a GPIO port, you typically enable only the pins which are interesting to generate an interrupt. If you can arrange only one pin of a port to be generating the interrupt, the job is done, your handler for that port can do the work, safely knowing that it will only be called when the right pin is active.
When you care about the cause within a single peripheral, and don't have the luxury of individually vectored handlers, you need to fall back on the 'non vectored' approach, and check the status registers before working out which eventual handler function needs to be called.
Interestingly, you can't work out which pin caused the interrupt - all you can see is which pins are still active once you get round to polling the status register. If you care about the phasing between two pulses, you may not be able to achieve this discrimination within a single GPIO unless there is dedicated hardware support. Even multiple exception vectors wouldn't help, unless you can be sure that the first exception is always taken before the second pin could become set.

What is the difference between "soft reset" and "hard reset" in embedded field?

In my opinion:
soft reset: boots from the reset vector.
hard reset: pull the electrical level of the cpu.
A hard reset certainly means that the whole CPU chip and all its peripherals are reset. The causes for this could be many: reset pin pulled externally, clock failures, on-chip low-voltage detection, watchdog, illegal instruction traps etc etc.
A soft reset probably means a "dirty" branch to back to the reset vector, where the reset vector restores all CPU core registers including the stack. I would say that this is very questionable practice and I'm not sure what good it would do. The main problem is that all MCU peripheral hardware registers will -not- get reset to default when you do this. It is almost impossible not to make any assumptions about the reset state of all such registers, especially since the average MCU comes with 1000+ of them nowadays. So with this soft & dirty reset, you will most likely end up a behaviour like this:
subtle intermittent bugs <= my program <= complete haywire
More far-fetched, a soft reset could mean a reset caused by software. In that case it could be writing the wrong value to the watchdog register to enforce a reset, or failing to refresh the watchdog. Or it could be the execution of an illegal instruction. These will most likely cause a complete reset of the whole chip.
This can very from chip to chip I assume. The hard reset is probably agreed to be the reset line on the device (pin, ball, etc) when pulled in a certain direction puts some or all of the chip in reset. Soft reset, could be as simple as a branch to zero or branch to the reset vector, or it could be a register you write or a bit in a register that causes a hard reset, or perhaps something close to a hard reset, imagine a layer inside the chip, the hard reset hits the outer layer, the soft reset hits some inside layer possibly not the whole chip. for example you maybe you dont want to fall off the pcie bus so you leave that alone. Normally jtag (or some portion of it) for example shouldnt be touched by either reset. When software pulls a reset line it kills itself, who is going to release that reset? Something in hardware, many ways to solve this, but if solved with something that has a digital component to it that digital section shouldnt get hit with the reset the software has hit or you again get stuck not being able to release it.
On an Intel platform, a soft reset (writing 0x4 to port 0xcf9) is a warm CPU reset, i.e. a reset while the CPU is running. A warm reset (writing 0x6 to port 0xcf9) is a host reset without a power cycle, and a hard reset (writing 0xe to port 0xcf9) is a host reset with a power cycle. A global reset is a reset of the Intel ME combined with a host reset.
A cold CPU reset is the assertion of RESET# while power is initially being supplied to the CPU. A warm CPU reset is when INIT# or RESET# occurs while V_cc and CLK remain in specified operating limits. If you just INIT# then it just flushes the BTB and TLBs and only initialises integer registers and goes to the restart MSROM routine (no longer just 0xFFFFFFF0 on UEFI systems). If you RESET# then it flushes the caches as well and initialises FP registers and not just the integer registers. This is the initial state of the registers, I think before the microcode begins. If you assert both INIT# and RESET# together then it does a BIST as well. I think in this case it reperforms the BSP selection process aka. the MP Initialisation protocol, because a BIPI is sent to all-including-self after the BIST completes, and I think it also performs BSP selection when there is no BIST i.e. just a RESET# when warm/cold (this talks about sending a BIPI after an optional BIST on reset). On modern Intel CPUs, I think RESET# is one per socket and resets all cores, and is tied to the PCH PLTRST#, whereas INIT is sent by the PCH over DMI in a PCIe VLW transaction, and is distributed on a core by core basis to the specified cores configured in a CPU register like QPIPNCB.
A warm reset is an assertion of PLTRST# by the PCH which goes to many components, and the system stays in S0. On a hard reset, the system cycles through SLP_S0# to SLP_S5# and then cycles up through SLP_S5# to SLP_S0# to end up in S0 C0 (when PLTRST# is eventually deasserted), this will result in DRAM being reset, which PLTRST# on its own doesn't do. SLP_S0 - S5# high means the CPU is in S0 C0. SLP_S0# low means it is in S0 Cx, SLP_S0# and SLP_S3# low means it is in S3, SLP_S0# and SLP_S3# and SLP_S4# low means it is in S4 and so on.
A cold reset I think is when the system boots from G3 and needs to go through PCH_RTCRST# and EC_RSMRST# before returning to the state it was in before the G3, which could be DeepSx, S5 or S4. But you will see people call the hard reset a cold reset, and the cold reset a cold boot. I would probably use the terms hard reset and cold boot. A warm boot would be a S3 resume and a cold boot would be booting from S4/S5/G3, maybe you could all S4/S5 a hard boot and G3 a cold boot.
It can mean whatever the system designer wants it to mean. There is no generic definition. For example, the content of RAM may be maintained through a soft reset, but not through a hard reset, or it may simply be the difference between an external hardware reset signal and a software RESET instruction.