Skocz do zawartości

ATmega328P tryb power-save sleep mode i błędy usarta


Anonim

Pomocna odpowiedź

 Z oscylatorem zewnętrznym nie ma problemu bo by się objawił od razu bez względu na sleep mode. sleep mode power-save nie zatrzymuje timera2 tylko odłącza oscylator taktujący rdzeń, pamięć itd. co wg. mnie może być przyczyną ale nie musi. Idle mode oscylatora (main clock source)  nie odłącza i prawdopodobnie dlatego nie pojawiają się wspomniane błędy.

Dodałem na początku delay 2s i nic to nie zmienia. Póki nie wchodzi w sleep wszystko działa jak trzeba, od pierwszego wejścia do sleep pojawia się ten błąd.

12 minut temu, marek1707 napisał:

A próbowałeś z zamkniętymi oczami przechodzić przez przejście z sygnalizacją? Wystarczy policzyć do 153 i "pewnie jest już wystarczająco zielone"?

Nie, nie próbowałem do tej pory. Ale kto wie co mi do głowy przyjdzie od nadmiaru sarkazmu.

20 minut temu, marek1707 napisał:

A przy jakim stosunku czasów startu oscylatora 32k do tego który mu na to dajesz zastanowiłbyś się chwilę, może puknął w głowę i poszukał prawidłowej sekwencji przełączania? Ciekaw jestem jakiejś liczby.

Z data sheetu :

Cytat

Warning: When switching between asynchronous and synchronous clocking of Timer/Counter2, the Timer
Registers TCNT2, OCR2x, and TCCR2x might be corrupted. A safe procedure for switching clock source
is:
a. Disable the Timer/Counter2 interrupts by clearing OCIE2x and TOIE2.
2. Select clock source by setting AS2 as appropriate.
3. Write new values to TCNT2, OCR2x, and TCCR2x.
4. To switch to asynchronous operation: Wait for TCN2xUB, OCR2xUB, and TCR2xUB.
5. Clear the Timer/Counter2 Interrupt Flags.
6. Enable interrupts, if needed.

więc wstawiłem jeszcze dla pewności

while(ASSR & _BV(TCR2BUB));

Niestety nic to nie zmienia względem tego błędu.

Zwróciłem też uwagę na ten fragment:

Cytat

Description of wake up from Power-save or ADC Noise Reduction mode when the timer is clocked
asynchronously: When the interrupt condition is met, the wake up process is started on the following cycle
of the timer clock, that is, the timer is always advanced by at least one before the processor can read the
counter value. After wake-up, the MCU is halted for four cycles, it executes the interrupt routine, and
resumes execution from the instruction following SLEEP.

I wg. tego nie powinno być żadnych problemów a próbowałem już różnie, nawet wstawiać niewielkie opóźnienia do przerwania

52 minuty temu, marek1707 napisał:

Po jakich 4ms? Po tym czasie to procesor rusza i dopiero wtedy włączasz wzmacniacz generatora 32k. Nie dajesz mu nawet 100us.

Faktycznie masz rację tylko to nie ma wpływu na ten błąd.

Link do komentarza
Share on other sites

Poprawiłem trochę to rękodzieło i teraz wygląda tak:

#define _NBV(b) ~_BV(b)
#define _SLEEP_ SMCR |= _BV(SE);asm("sleep")
  
void 
rswrite(char *ch){

	for(; *ch; ch++){
		while (!(UCSR0A & _BV(UDRE0)));
		UDR0 = *ch;
	}
  	while (!(UCSR0A & _BV(UDRE0)));
}

int 
main(void){
// rtc z kwarcu 32.786kHz
  	ASSR 		|= _BV(AS2);
  _delay_ms(1000);
	TCNT2 		= 0;
  while(ASSR & _BV(TCN2UB));
  	TCCR2B 		|= _BV(CS21);//presc 8 -> 0.0625s (1/16s)
  while(ASSR & _BV(TCR2BUB));
  	TIFR2 		|= _BV(TOV2);// !
	TIMSK2		|= _BV(TOIE2);

// sleep
    SMCR |= _BV(SM1)|_BV(SM0);
  
// usart 9600
  	UBRR0H = 0;
	UBRR0L = 51;
	UCSR0A &= _NBV(U2X0);
	
	UCSR0C |= _BV(UPM01)|_BV(UCSZ01) | _BV(UCSZ00); // even parity, 8bit char size, 1 bit stop 
	UCSR0B |= _BV(TXEN0) | _BV(RXEN0) | _BV(RXCIE0);
  
// zmienne  
 	uint8_t txtbuff[8];
  	uint8_t	seconds;
	uint8_t	minuts;
	uint8_t hour;
	uint8_t day;
  
  sei();
// Loop  
  while(1){
    
    if(RTC_FLAG_REG & _BV(RTC_SEC_FLAG)){ 
      
			MAIN_FLAG_REG &= _NBV(RTC_SEC_FLAG);
			seconds++;
			if(seconds == 60){
				seconds = 0;
				minuts++;
				if(minuts == 60){
					minuts = 0;
					hours++;
					if(hours == 24){
						hours = 0;
						days++;
					}
				}
			}
			rswrite("day: ");
			rswrite(itoa(days,txtbuff,10));
			rswrite("\r\n");
    		
      		if(hours < 10) rswrite("0"); 
      		rswrite(itoa(hours,txtbuff,10)); rswrite(":");
      		if(minuts < 10) rswrite("0");
      		rswrite(itoa(minutss,txtbuff,10)); rswrite(":");
      		if(seconds < 10) rswrite("0");
			rswrite(itoa(seconds,txtbuff,10));
			rswrite("\r\n");
    }
   if(seconds>15)_SLEEP_;
  }
  
}

ISR(TIMER2_OVF_vect, ISR_NAKED){
 
	asm volatile(
		"cbi _SFR_IO_ADDR(SMCR), 0		\n\t"		
		"push r24						\n\t"
		"push r25						\n\t"
		"push __tmp_reg__				\n\t"
		"in __tmp_reg__,__SREG__		\n\t" 
		"in r25, %0						\n\t"
		"mov r24, r25					\n\t"
		"andi r24, 0x1F					\n\t"
		"inc r24						\n\t"
		"cpi r24, 16					\n\t"
		"brne exit						\n\t"
			"ori r25, (1<<5)			\n\t"
			"clr r24					\n\t"
	"exit:								\n\t"
		"or r25, r24					\n\t"
		"out %0, r25					\n\t"
		"out __SREG__,__tmp_reg__		\n\t"  
		"pop __tmp_reg__				\n\t"
		"pop r24						\n\t"
		"reti							\n\t"
		:
		: "I" (_SFR_IO_ADDR(GPIOR0))  // główny rejestr flag
		:"r24", "r25"
	);
};

Niestety nie przeskoczyłem problemu a próbowałem delaye wstawiać w różnych miejscach, zamienić rejestr flag ze sprzętowego na zmienną volatile, przestawiać kolejniść inicjalizacji za każdym razem z podobnym rezultatem albo gorszym. Dodałem if przed wejściem w sleep-mode żeby było wyraźnie widać w czym tkwi problem.

Po 15 cyklu włącza się sleep a terminal wypluwa z siebie coś takiego:

pwr_sve_arduino.png

pwr_sve_realterm.png

Link do komentarza
Share on other sites

Chciałem na szybko i wyszło jak zwyklę. Poświęciłem chwilę czasu na wymyślanie koła od nowa i opanowałem temat a nawet dowiedziałem się czegoś nowego. Nie przypuszczałem, że będę musiał ponownie od podstaw zmagać się z atmegą i różnymi niuansami z nią związanymi. Swego czasu miałem opracowane rozwiązania takich różnych problemów związanych z avr  niestety przepadły razem z pamięcią masową.

23 godziny temu, kaczakat napisał:

Program to dla mnie chińskie krzaczki, ale po wybudzeniu czas w uC leci tak jakby prawie 3x szybciej.

Było to spowodowane brakiem opóźnienia zaraz po wybudzeniu. Okazało się, że kiedy nie zaczeka się na ustabilizowanie oscylatora wewnętrznego to rejestry sprzętowe nie funkcjonują prawidłowo nawet kiedy już oscylator się rozpędzi. Wystarczyło wprowadzić odpowiednie opóźnienie. Problem z usartem też został rozwiązany. Okazało się, że również wystarczył niewielki delay na końcu i czyszczenie bufora.. odbiorczego. (sic)

W komentarzach dodatkowe info.

Poprawiony program nie zawiera już "baboli"  i może komuś oszczędzi czas kiedy będzie chciał zrobić zegarek z płytki arduino.


/// Includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h>
/// Defines
#define _NBV(bit) 			~_BV(bit)
#define delay_us_(cnt) 		for(uint16_t c=(cnt);c;--c){\
							asm volatile("nop"::);\
							asm volatile("nop"::);\
							asm volatile("nop"::);\
							asm volatile("nop"::);}
// power-save sleep mode
#define _SLEEP_ 			SMCR |= _BV(SM1)|_BV(SM0)|_BV(SE);\
							asm volatile("nop");\
							asm volatile("sleep")
/// Flags
// G³ówny rejestr flag, pierwsze 5 bitów na licznik przerwañ do 16
#define MAIN_FLAG_REG 		GPIOR0 
//////////////////////////////////
#define RTC_SEC_FLAG 		5



void 
usart_put_string(char *string){
	char garbage = 0;
	garbage |= garbage ;
    /// Mimo iz receiver jest wylaczony to jednak zbiera 
	/// smiecie podczas wybudzania a pozniejniej sa one przepisywane do 
	/// do wspoldzielonego rejestru UDR0  ( coz za niespodzianka!  )
	DDRD |=  _BV(PD1);		//output						
	UCSR0B |= _BV(TXEN0);
	asm  volatile("nop"::);	
	for(; *string; string++){
	
		while (!(UCSR0A & _BV(UDRE0)));	// oczekiwanie na oproznienie bufora nadawczego
		garbage = UDR0;					// czyszczenie bufora
		UDR0 = *string;	
	}
	while (!(UCSR0A & _BV(UDRE0))); 	// zglasza gotowosc bufora ale dane sa nadal wysylane... 				   
	UCSR0B &= _NBV(TXEN0);
	DDRD &=  _NBV(PD1);			   		//input -> Tx fizycznie podciagniety do VDD przez 3k3
	PORTD |= _BV(PB1);			   		//pullup bo szkoda pradu
	
}
/*
// HD44780 
const char 
battery_font[6][8] PROGMEM = {
{0x1F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F}, // empty-
{0x1F, 0x18, 0x18, 0x1C, 0x1C, 0x1C, 0x1E, 0x1F}, // half-
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // full-
{0x1E, 0x02, 0x03, 0x01, 0x01, 0x03, 0x02, 0x1E}, // empty+
{0x1E, 0x12, 0x13, 0x11, 0x19, 0x1B, 0x1A, 0x1E}, // half+
{0x1E, 0x1E, 0xFF, 0xFF, 0xFF, 0xFF, 0x1E, 0x1E}};// full+
*/
/// ////////////////////////////////////////////////////////
int 
main(void){
/// Init:
//RTC
	ASSR 		|= _BV(AS2);
	TCNT2 		= 0;
	while(ASSR & _BV(TCN2UB));
	TCCR2B 	|= _BV(CS21);// 8 -> 0.0625s (1/16s)
	while(ASSR & _BV(TCR2BUB));
	TIFR2 		|= _BV(TOV2);
	TIMSK2		|= _BV(TOIE2);
	
//USART
	UBRR0H = 0;
	UBRR0L = 51; // baud 9600
// even parity_BV(UPM01)|, 2 bity stopu _BV(USBS0), 8bit char size _BV(UCSZ01) | _BV(UCSZ00)
	UCSR0C |= _BV(USBS0)|_BV(UCSZ01) | _BV(UCSZ00); 
	UCSR0B |= _BV(TXEN0); //| _BV(RXEN0) | _BV(RXCIE0);

// UCSR0A & _BV(FE0)  // frame error
// UCSR0A & _BV(UPE0) // parity error
// UCSR0A & _BV(DOR0) // data overrun error
// UCSR0A & _BV(UDRE0) // data register empty, mo¿na ³adowaæ kolejny bajt

	sei();
	char txt_buff[8];
	uint8_t seconds = 0;
	uint8_t minuts = 0;
	uint8_t hours = 0;
	uint16_t days = 0;
	
/// Loop:
	while(1){
		
		if(MAIN_FLAG_REG & _BV(RTC_SEC_FLAG)){
		
			MAIN_FLAG_REG &= _NBV(RTC_SEC_FLAG);
			seconds++;
			if(seconds == 60){
				seconds = 0;
				minuts++;
				if(minuts == 60){
					minuts = 0;
					hours++;
					if(hours == 24){
						hours = 0;
						days++;
					}
				}
			}
			usart_put_string("day: ");
			usart_put_string(itoa(days,txt_buff,10));
			if(hours < 10)usart_put_string("\r\n0");
			usart_put_string(itoa(hours,txt_buff,10)); usart_put_string(":");
			if(minuts < 10)usart_put_string("0");
			usart_put_string(itoa(minuts,txt_buff,10));usart_put_string(":");
			if(seconds < 10) usart_put_string("0");
			usart_put_string(itoa(seconds,txt_buff,10));
			usart_put_string("\r\n");	
		}
		delay_us_(1042); // Trzeba czekac, az usart wysle wszystkie znaki
		_SLEEP_;
	}
	
}
///////////////////////////////////

ISR(TIMER2_OVF_vect, ISR_NAKED){	
	asm volatile(
		"push __tmp_reg__ 				\n\t"
		"in __tmp_reg__,__SREG__		\n\t"  // przepisz sreg
		"push r24 						\n\t"
		"clr r24						\n\t"
		"out %0, r24 					\n\t" // wylacz sleep mode
		"push r25 						\n\t"
		"ldi	r24, 30					\n\t"
		"clr	r25						\n\t"
"delay_us:								\n\t" // 30us na ustabilizowanie taktowania rejestrów sprzêtowych
		"nop							\n\t"
		"nop							\n\t"
		"nop							\n\t"
		"nop							\n\t"
		"sbiw	r24, 1					\n\t"
	"brne delay_us						\n\t"		
		"in r25, %1						\n\t"
		"mov r24, r25					\n\t"
		"andi r24, 0x1F					\n\t"
		"andi r25, 0xE0					\n\t"
		"inc r24						\n\t"
		"cpi r24, 16					\n\t"
	"brne exit111						\n\t"
		"ori r25, (1<<5)				\n\t"
		"clr r24						\n\t"
"exit111:								\n\t"
		"or r25, r24					\n\t"
		"out %1, r25					\n\t"
		"out __SREG__,__tmp_reg__ 		\n\t"  // przywroc poczatkowy stan sreg , [FLAGS] "=m" (_SFR_IO_ADDR(GPIOR0))
		"pop r25						\n\t"
		"pop r24						\n\t"
		"pop __tmp_reg__				\n\t"
		"reti							\n\t"
		:
		:"I"(_SFR_IO_ADDR(SMCR)),
		 "I" (_SFR_IO_ADDR(GPIOR0))
		:"r24", "r25"
	);
};

 

Dnia 3.06.2019 o 14:26, marek1707 napisał:

"pewnie jest już wystarczająco zielone"?

a jest?

Dnia 3.06.2019 o 14:26, marek1707 napisał:

Ciekaw jestem jakiejś liczby.

@marek1707 są już liczby. Jak by Ci się chciało to rzuć okiem fachowca.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.