ATMega128 Output Flicker on Startup - c

I'm using an ATMega128 micro and have all of my pin inits set to output and set to low under my main section of code:
PORTB=0x00;
DDRB=0xFF;
However on startup, the output associated with PORTB.0 flicks high for a split second (I've caught it on the scope) and it seems the other outputs are doing the same. Seems like it goes LOW-HIGH-LOW. I've done some reading that it could be caused by the tri-state to output switch during startup, so I've set the PUD register to 1 before the pin inits and then back to 0 after and still no luck. Does anyone have any other ideas to keep that output off during startup? It doesn't always occur either which is what has me stumped.

The fundamental problem is a hardware issue - lack of a pull-down resistor on the GPIO so that it is floating when in the reset-default high-impedance input state.
The best you can do in software is to initialise the GPIO at the earliest opportunity immediately after the reset. To do this in CodeVisionAVR you need to use a customised startup.asm in your project as described in section 4.18 of the CoadeVisionAVR compiler manual:
...
Where I suggest you initialise PORTB and DDRB as follows:
LDI R16, 0x00
OUT PORTB, R16
LDI R16, 0xFF
OUT DDRB, R16
immediately before step 2, i.e. the first four instructions. The amount of time the GPIO will be left floating will possibly be too small for the relay to react if it is a mechanical relay. You may still have a problem for a solid state relay. The length of any pulse may depend on the power-supply rise time; if it is slow, you may get a longer pulse.

Related

Wondering how to strangely preset the value of Timer0?

May I ask when setting the value for Timer0 why in some cases people have to use subtraction to represent the preset Timer0 instead of using its result directly (in this case, 175 )? And in this case what is the purpose of the UL suffix?
Examble:
X=255Ul-80;
void interrupt ISR(void)
{
     if (T0IF)
    {
         T0IF=0;
         TMR0=X;
         abc();
    }
}
...
The Microchip documentation describes how the TIMER0 module works.
It does not describe methods of how to use this counter/timer module very well.
The fundamental architecture of the TIMER0 module is very primitive when compared to any modern embedded controller today. It is unclear why Microchip persists with including this counter/timer module in new 8-bit PIC controllers. Understand that 35 years ago it was a challenge to maximize functionality with the minimum number of transistors so that each controller chip would be as small as possible and yield the most chips per wafer.
The way TIMER0 works is as an up counter. When first implemented the controller did not support interrupts at all. See baseline controllers like the PIC12F508. The mid-range controllers like the PIC16F877 added support for interrupts and TIMER0 acquired the functionality to request an interrupt when the 8-bit count register rolled over from 0xFF to 0x00. It takes 256 counts for TIMER0 to assert an interrupt request when the TIMER0 count register starts at 0x00. When the interrupt needs to be asserted after a specific number of counts set the count register to the value of 256-(Specific_Number_Of_Counts) then clear the TIMER0 interrupt request.
This feature is used by developer to have the TIMER0 interrupt request assert after a specific number of counts.
There is an "off-by-one" error in the example in you question:
X=255Ul-80;
As the TIMER0 count register will have the value of 0xFF after 80 counts and the TIMER0 interrupt request will be set after 81 counts.
The example code in your question "suggests" that you want the "abc()" function invoked after TIMER0 have been clocked 80 times. The function will actually be invoked after TIMER0 have been clocked 81 times.
Also note that the simulation model for TIMER0 does not have a cycle accurate implementation so does not simulate the actual accurately. This simulation flaw exists in all releases of MPLABX for 8-bit PIC controllers. Be warned that the simulator will not provide cycle counts that match the real world hardware.

Read non conventional ADC with STM32F3

I'm attempting to interface an STM32F303 Nucleo with an AD7748-4 ADC. Datasheet for the ADC:
https://www.analog.com/media/en/technical-documentation/data-sheets/ad7768-7768-4.pdf
The issue is, the ADC DOES NOT output the converted value through the SPI port, but rather employs a Data Ready Signal (DRDY), a Data Clock (DCLK), and a combination of 4 Data Outputs (DOUT0-DOUT3). The output streams 96 bits serially through one wire if I set it up that way, but timing is critical in my application and I need to clock the data in using DOUT0 to DOUT2, which would each output 32 bits. If I were serially streaming the data, I could trick the SPI port into reading it, but I'm not. The ADC is running at 20MHz, so DCLK will be operating at the same frequency. The Nucleo runs at a maximum of 72MHz, but when the DAM is utilized, it sets the clock to 64MHz.
In the STM manual, it describes a "GPIO port input data register (GPIOx_IDR) (x = A..H)" as being a read only register - my understanding is that the lower 16 bits can store an inputted value up to 16 bits (most likely for memory data R/W) - so the question is, how can I configure the GPIO to read in the data? I'm at a slight impass here. My instinct tells me that the Nucleo may not be fast enough to read the data coming from the ADC... Any ideas? All being written in C/C++ basically bare metal... I'm new to the Nucleo, haven't written code in 4 years - pardon any lapse in knowledge...
If DCLK works at 20Mhz, the uC is obviously not fast enough (you have about 3 instructions between each cycle, so even assembly language would be difficult to implement...). As I am not familiar with the stm architecture, I can only suggest a trick that will maybe spark some ideas in your head. Rather than using a crystal for the ADC, use a timer from the STM that is connected to an output pin, and clock the ADC using that pin (MCLK). When configuring the ADC using spi, idle mode, etc. you can leave this clock signal at 20Mhz. But when you need a sample from the ADC, stop the STM timer and clock the ADC "manually". (you practically control the DCLK signal). After your conversion routine is over, restart the timer at 20Mhz.

Why NOP/few extra lines of code/optimization of pointer aliasing helps? [Fujitsu MB90F543 MCU C code]

I am trying to fix an bug found in a mature program for Fujitsu MB90F543. The program works for nearly 10 years so far, but it was discovered, that under some special circumstances it fails to do two things at it's very beginning. One of them is crucial.
After low and high level initialization (ports, pins, peripherials, IRQ handlers) configuration data is read over SPI from EEPROM and status LEDs are turned on for a moment (to turn them a data is send over SPI to a LED driver).
When those special circumstances occur first and only first function invoking just a few EEPROM reads fails and additionally a few of the LEDs that should, don't turn on.
The program is written in C and compiled using Softune v30L32.
Surprisingly it is sufficient to add single __asm(" NOP ") in low level hardware init to make the program work as expected under mentioned circumstances. It is sufficient to turn off 'Control optimization of pointer aliasing' in Optimization settings. Adding just a few lines of code in various places helps too.
I have compared (DIFFed) ASM listings of compiled program for a version with and without __asm(" NOP ") and with both aforementioned optimizer settings and they all look just fine.
The only warning Softune compiler has been printing for years during compilation is as follows:
*** W1372L: The section is placed outside the RAM area or the I/O area (IOXTND)
I do realize it's rather general question, but maybe someone who has a bigger picture will be able to point out possible cause.
Have you got an idea what may cause such a weird behaviour? How to locate the bug and fix it?
During the initialization a few long (about 20ms) delay loops are used. They don't help although they were increased from about 2ms, yet single NOP in any line of the hardware initialization function and even before or after the function helps.
Both the wait loops works. I have checked it using an oscilloscope. (I have added LED turn on before and off after).
I have checked timming hypothesis by slowing down SPI clock from 1MHz to 500kHz. It does not change anything. Slowing down to 250kHz makes watchdog resets, as some parts of the code execute too long (>25ms).
One more thing. I have observed that adding local variables in any source file sometimes makes the problem disappear or reappear. The same concerns initializing uninitialized local variables. Adding a few extra lines of a code in any of the files helps or reveals the problem.
void main(void)
{
watchdog_init();
// waiting for power supply to stabilize
wait; // about 45ms
hardware_init();
clear_watchdog();
application_init();
clear_watchdog();
wait; // about 20ms
test_LED();
{...}
}
void hardware_init (void)
{
__asm("NOP"); // how it comes it helps? - it may be in any line of the function
io_init(); // ports initialization
clk_init();
timer_init();
adc_init();
spi_init();
LED_init();
spi_start();
key_driver_init();
can_init();
irq_init(); // set IRQ priorities and global IRQ enable
}
Could be one of many things but two spring to mind.
Timing.
Maybe the wait is not long enough for power to stabilize and not everything is synced to the clock. The NOP gets everything back in sync.
Alignment.
Perhaps the NOP gets your instructions aligned on a 32 or 64 bit boundary expected by the hardware. (we used to do this a lot on mainframe assemblers as IO operations often expected things to be on double word boundarys).
The problem was solved. It was caused by a trivial bug.
EEPROM's nHOLD and nCS signals were not initialized immediately after MCU's reset, but before the first use of the EEPROM. As a result they were 0's, so active.
This means EEPROM was selected, but waiting on hold. Meantime other transfer using SPI started. After 6 out of 8 CLK pulses EEPROM's nHOLD I/O pin was initialized and brought high. EEPROM was no longer on hold so it clocked in last two bits of a data for an other peripheral. Every subsequent operation on the EEPROM found it being having not synchronized CLK and MOSI.
When I have added NOP or anything other the moment of nHOLD 0->1 edge was shifted to happen after the last CLK pulse. Now CLK-MOSI were in sync.
All I have had to do was to initialize all the EEPROM's SPI lines, in
particular nHOLD and nCS right after the MCU reset.

AVR/Arduino: reading timer toggled port pin

I've configured the timer 2 in CTC mode and to toggle the port pin on compare match (TCCR2A=0x42, TCCR2B=0x02, OCR2A=0x20) and have set DDR3 to output. Hence, according to the ATmega328P documentation (pages 158-163). OC2A (aka PB3) should toggle on each compare match. Unfortunately, I can't read the pin state at PORTB. Is this expected? I assumed, that even if a port is configured as output I can read the set value.
There were two problems:
In AVR Studio 4.18 I must not use the Simulator 1, because it has a bug for the timer 2 and hence can't toggle the port pin correctly. I needed to use Simulator 2 or AVR Studio 5.
I needed to read PINB instead of PORTB (though the toggling is an output operation).
I don't know about that specific microcontroller, but in some architectures you need at least a NOP between changing the port pin and the latch being updated (so you can read the change).
Also there is the maximum frequency a pin can be toggled at (many times slower than the microcontroller CPU clock). Be sure to not be over that frequency.

How to detect cold boot versus warm boot on an ARM processor?

I'm looking for a way to determine whether an ARM processor is booting from a cold boot (i.e. initial power-on) versus a warm boot (i.e. reset assertion without actual power loss). Specifically I'm using an ARM968 core, will be making the determination using C or assembly, and I will use the determination so certain operations only run on the initial power-on and not on subsequent resets. In previous projects I've leveraged external circuitry (e.g. FPGA) to detect the different boot scenarios, but in this case I am limited to the ARM core.
Check the docs for you specific chip ("ARM968" is not specific enough). There should be a register that describes the cause of reset. E.g. here's what LPC23xx has:
Reset Source Identification Register (RSIR - 0xE01FC180)
This register contains one bit for each source of Reset. Writing a 1 to any of these bits
clears the corresponding read-side bit to 0. The interactions among the four sources are
described below.
Bit Symbol Description
0 POR Assertion of the POR signal sets this bit, and clears all of the other bits in
this register. But if another Reset signal (e.g., External Reset) remains
asserted after the POR signal is negated, then its bit is set. This bit is not
affected by any of the other sources of Reset.
1 EXTR Assertion of the RESET signal sets this bit. This bit is cleared by POR,
but is not affected by WDT or BOD reset.
2 WDTR This bit is set when the Watchdog Timer times out and the WDTRESET
bit in the Watchdog Mode Register is 1. It is cleared by any of the other
sources of Reset.
3 BODR This bit is set when the 3.3 V power reaches a level below 2.6 V.
If the VDD(DCDC)(3V3) voltage dips from 3.3 V to 2.5 V and backs up, the
BODR bit will be set to 1.
If the VDD(DCDC)(3V3) voltage dips from 3.3 V to 2.5 V and continues to
decline to the level at which POR is asserted (nominally 1 V), the BODR
bit is cleared.
if the VDD(DCDC)(3V3) voltage rises continuously from below 1 V to a level
above 2.6 V, the BODR will be set to 1.
This bit is not affected by External Reset nor Watchdog Reset.
Note: Only in case when a reset occurs and the POR = 0, the BODR bit
indicates if the VDD(DCDC)(3V3) voltage was below 2.6 V or not.
You can initialize a global variable in RAM to a value that is unlikely during cold boot, and check for that during boot.
For microcontrollers normally the reset logic of the specific chip provides a status register, which indicates the source of the reset. I don't know if that exists for this bigger core, and whether you could use that.
It is likely to be difficult, and maybe you dont really mean just the core itself. The core should have gotten a reset, but the memory outside (but perhaps still within the chip) did not. if the memory is dram based then it may still get wiped on boot. I dont know of a generic one size fits all answer. both you and starblue have it though, you have to find some register somewhere that is not cleared on a reset, set that to something that is "likely" not to happen randomly on a power up. read it then set it. thinks like the fpga or pld that manage the reset logic at the board level (if any) are the best because on a power on reset they are reset as well, and on a warm reset they are the one that caused it and keep their state.
dig through the TRM for your core or through the register spec for the chip, and see if there are any registers whose reset state is undefined, one that you normally dont use and wont hurt the chip if you set it to something, and see what it powers up as, that is where I would start looking.

Resources