The code is better or at least more elaborate..
Lots more comments as I have read more detail about how the USART works in the 328 and the 168.
Clears registers :).
The corruption on the serial port is reduced a bit.
if you send 'ccccccccccccccccccccccccpr' as one string then the last character of the printed data is not properly
flushed through the usart when the reset happens, and the next time i send a 'p' a garbage character is printed in place of the newline.
I think the change that I made with most effect was to comment out UDR0 = 0 ;
when I realised that it was a bi-directional register.
I have still not worked out how to drain the transmit path.. i almost think it mioght not be possible
But, it is getting closer I think, and I know some more, and having fun.
Now I have registers cleared, and most of the USART code right (i think) next is to review the other devices.
Regards,
Dave
#define GREEN_LED 7 // flickers fast
#define RED_LED 8 // slow flicker
#define YELLOW_LED 9 // more of a flash
void setup()
{
Serial.begin(115200) ;
pinMode(GREEN_LED, OUTPUT) ;
pinMode(RED_LED, OUTPUT) ;
pinMode(YELLOW_LED, OUTPUT) ;
digitalWrite(GREEN_LED, 1) ;
digitalWrite(RED_LED, 1) ;
digitalWrite(YELLOW_LED, 1) ;
}
#ifdef simple_reset
void (*sketchRestaRt)(void) = 0x0000;
#else
#include <avr/io.h>
void sketchRestart(void)
{
noInterrupts() ; // no interrupts while adjusting register values.
// SET ALL DOCUMENTED REGISTERS TO THEIR POWER ON VALUES.
MCUSR = 0 ; // no reset source
WDTCSR = 0 ; // no watch dog resets
EICRA = 0 ; // no external interrupts
EIMSK = 0 ; // external interrupt mask cleared
EIFR = 0 ; // external interrupt flag register - no pending interrupts
PCICR = 0 ; // pin change interrupt control register
PCIFR = 0 ; // pin change interrupt flag register
PCMSK2 = 0 ; // pin change mask register 2
PCMSK1 = 0 ; // pin change mask register 1
PCMSK0 = 0 ; // pin change mask register 0
// port B
DDRB = 0 ;
PORTB = 0 ;
// PINB not defined.
// port C
DDRC = 0 ;
PORTC = 0 ;
// PINC not defined
// port D
DDRD = 0 ;
PORTD = 0 ;
// PIND not defined
// timer prescalers (timer 0 and 1)
GTCCR = 0 ;
// Timer - 0
TCCR0A = 0 ;
TCCR0B = 0 ;
TCNT0 = 0 ;
OCR0A = 0 ;
OCR0B = 0 ;
TIFR0 = 0 ;
TIMSK0 = 0 ;
// Timer - 1
TCCR1A = 0 ;
TCCR1B = 0 ;
TCCR1C = 0 ;
TCNT1 = 0 ; // 16 bit
OCR1A = 0 ; // 16 bit
OCR1B = 0 ; // 16 bit
ICR1 = 0 ; // 16 bit
TIFR1 = 0 ;
TIMSK1 = 0 ;
// Timer - 2
TCCR2A = 0 ;
TCCR2B = 0 ;
TCNT2 = 0 ;
OCR2A = 0 ;
OCR2B = 0 ;
TIFR2 = 0 ;
TIMSK2 = 0 ;
// Assynchronous Status Register (timer 2 stuff)
ASSR = 0 ;
// SPI
SPCR = 0 ;
SPSR = 0 ;
// SPDR undefined on restart
// usart0
if ( UCSR0B & (1<<RXEN0)) // if recieve enabled, drain the input buffers
{
unsigned char dummy;
while ( UCSR0A & (1<<RXC0) ) dummy = UDR0; // while data present read from receive queue
}
if (UCSR0B & (1<<TXEN0)) // if transmit enabled
{
// Try to to drain the transmit fifo; sometimes we do not succeed, we leave the data
// in the shift register and change the settings, leading to garbage on the line.
// This code is not sure to work, as it is not possible to reliably tell if
// there is data in the trasmit shift register.
// The bit TXC0 is cleared after a transmit interrupt is sent, and can be cleared by code.
// If the TXC0 bit is clear, it could mean that there is data waiting to be sent or that there isn't.
// If the TXC0 bit is set, there is no data to send.
// The only reliable signal that there is more data to send is the UDRE0 bit which indicates that one and
// a part characters are waiting to be sent.
if ((UCSR0A & (1<<UDRE0)) == 0) // there is a byte in the transmit fifo
{
while ((UCSR0A & (1<<UDRE0)) == 0) // while transmit queue is not empty
; // drain the transmit buffer
while ((UCSR0A & (1<<TXC0)) == 0) // transmit of last character not yet complete
; // and wait for the transmit shift buffer to empty
}
}
// the UDR0 register supplys the data for both input and output side of UART comms..
// UDR0 = 0 ; // would be transmitting a null :( - leads to corruption because we are about to set the speed to 1M Bit/second.
// if I put this back the garbage is much more :)
UCSR0A = 0 ; // RXC0 bit is clear due to read queue draining above
// TXC0 bit is cleared by assinment to 0.
// UDRE0 bit is read only, and 1 according the restart normal logic
// UDRE0 bit should be 1 if transmit was enabled because of the transmit fifo draining above.
// FE0 (frame error) is cleared by draining the read queue
// DOR0 (data over run) is cleared by draining read queue
// UPE0 (usart parity error) is cleared by draining the read queue
// U2X0 (double baud rate) is set to zero by assignment of 0
// MPCM0 (multi-processor communication mode) cleared by to zero by assignment of 0
UCSR0B = 0 ; // no recieve interrupt, no TX complete interrupt, no UDR empty interrupt, reciever disabled, transmitter disabled,
// ! 9bit chars, 9th bit in =0, 9th bit out=0
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00) ; // reset values are these bits; // 8 bit characters
// UMSEL01, UMSEL00 - bits are 0, indiactes Asynchronous USART
// UPM01, UPM00 - bits are 0, partity disabled.
// USBS = 0, one stop bit
// UCSZ01, UCSZ02 - bits are 1, implies 8 bits per character.
// UCPOL0, bit is 0, asynchronous mode.
UBRR0L = 0 ; // baud rate is clock divided by 16
UBRR0H = 0 ; //
// two wire interface - more to check
TWBR = 0 ;
TWCR = 0 ;
TWSR = 0 ;
TWDR = 0xff ; // this write might not suceed. Is only writeable when TWI is not shifting a byte.
// maybe should disable twi as early as possible, so more chance this instruction works.
TWAR = ~(_BV(TWGCE)) ; // all bits except TWGCE set.
TWAMR = 0 ;
// analog comparator
ADCSRB = 0 ;
ACSR = 0 ;
DIDR1 = 0 ;
// ADC
ADMUX = 0 ;
ADCSRA = 0 ;
ADCSRB = 0 ;
DIDR0 = 0 ;
// ADCL = 0 ; // read only
// ADCH = 0 ; // read only
// debugWire - not accessible outside debugWire
// DWDR = 0 ; // might be prohibited from setting this.
// flash access control
SPMCSR = 0 ;
asm volatile ("clr r0") ;
asm volatile ("clr r1") ;
asm volatile ("movw r2, r0") ;
asm volatile ("movw r4, r0") ;
asm volatile ("movw r6, r0") ;
asm volatile ("movw r8, r0") ;
asm volatile ("movw r10, r0") ;
asm volatile ("movw r12, r0") ;
asm volatile ("movw r14, r0") ;
asm volatile ("movw r16, r0") ;
asm volatile ("movw r18, r0") ;
asm volatile ("movw r20, r0") ;
asm volatile ("movw r22, r0") ;
asm volatile ("movw r24, r0") ;
asm volatile ("movw r26, r0") ;
asm volatile ("movw r28, r0") ;
asm volatile ("movw r30, r0") ;
interrupts() ;
asm volatile ("jmp 0") ;
}
#endif
static int static_variable = 0 ;
static unsigned long counter = 0 ;
void loop()
{
counter++ ;
if ((counter % (16u*1024LU)) == 0UL) // every 16k thru the loop
{
digitalWrite(GREEN_LED, (counter % (32u*1024UL)) == 0UL) ; // togle green
if ((counter % (32u*1024UL)) == 0UL) // every 32k times
{
digitalWrite(RED_LED, (counter % (64u*1024UL)) == 0UL) ; // toggle red
if ((counter % (64u*1024UL)) == 0UL) // every 64k times
digitalWrite(YELLOW_LED, (counter % (128u*1024UL)) == 0UL) ; // toggle yellow
}
}
if(Serial.available()) // a character is waiting
{
switch(Serial.read())
{
case 'r':
sketchRestart() ; // call the start of myself:)
break ; // dosnt get here
case 'c':
static_variable ++ ; // count my 'c's
break ;
case 'p':
Serial.print("static_variable = ") ;
Serial.println(static_variable) ;
Serial.print("loop counter = ") ;
Serial.println(counter) ;
break ;
}
}
}