ATxMega256A3BU & RTC32

OP #4748478
Lesenswert?

Guten Morgen,

Bin schon seit Tagen dabei, eine RTC mit der internen Hardware vom xMega 
zu realisieren.
Benutzen tue ich ein XPLAINED Board mit einem LCD.
Der xMega besitzt auch eine externe Batterie. Nun Soll es damit wohl 
möglich sein, die Uhrzeit zwischen zu speichern. Wie genau funktioniert 
das. Wie zähle ich die Zeit weiter, wenn VCC nicht mehr vorhanden ist?
Gast #4748647
Lesenswert?

Nimm dir doch das Beispielprojekt dazu heran... da ist doch alles 
realisiert. Jedenfalls bei dem Xplained ohne LCD ist es verwendet. Wenn 
die extra mit Batterie ausliefern, dann wird es bei deinem Board wohl im 
Beispielprojekt ebenfalls verwendet werden.
Gast #4748818
Lesenswert?

Google mal nach AVR Appnote 1321 da ist ein Bisschen was beschrieben.
Ich habe vorige Woche mich genau durch diesen Kram gefräst..

Du brauchst die VBAT Initialisierungsgeschicht aus der Appnote:
1
* Depending on the VBAT system check appropriate actions need to 
2
        * be taken.
3
        * In this example we re-initialize the VBAT system in all
4
        * error cases.
5
        */
6
        switch (vbat_status)
7
        {
8
        case VBAT_STATUS_OK:
9
                // Interrupts must be re-enabled
10
                //RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_LO_gc);
11
                RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_OFF_gc);
12
                break;
13
        case VBAT_STATUS_NO_POWER: // fall through
14
        case VBAT_STATUS_BBPOR: // fall through
15
        case VBAT_STATUS_BBBOD: // fall through
16
        case VBAT_STATUS_XOSCFAIL: // fall through
17
        default:
18
                vbat_init();
19
                break;
20
        }

..und ja, ich habe auch an mir gezweifelt, die Manuals sind nicht 
übermäßig didaktisch geschrieben.. aber bei mir funzt das indessen
(auf anderer Hardware).


Gruß,

Holm
Gast #4749570
Lesenswert?

Die RTC32 ist ein 32Bit counter der mit Batteriepower weiterlaufen kann,
bei Sekundentakt läuft der nach 168 Jahren (?) über, bis dahin mußt Du 
Dir um die Zeit keine Sorgen machen.

Umrechnen der Sekunden nach Zeit mittels mktime() und gmtime() (oder 
localtime etc..). Interrupts sind nicht unbedingt notwendig.

Gruß,

Holm
Gast #4749645
Lesenswert?

hole Dir doch mal die Appnote und das dazugehörige Zip Archiv, die 
Funktionen sind darin dokumentiert und das Ganze darfst Du ja auch 
benutzen.

Suche nach AVR1321 z.B. bei Atmel auf der Webseite unter den Dokuementen 
zum AtXmega.

Das was Du suchst steht in rtc32_driver.c
1
/*! \brief This function returns the current RTC count value.
2
 *
3
 *  This function synchronizes the RTC32 module's CNT value to the system
4
 *  clock domain, then returns its value.
5
 *
6
 *  \return The current RTC count value.
7
 */
8
uint32_t RTC32_GetCount( void )
9
{
10
        /* Synchronize the RTC module's CNT value to the system clock domain.  */
11
        RTC32_SyncCnt();
12
        do { } while ( RTC32_SyncCntBusy() );
13
        
14
        return RTC32.CNT;
15
}

Gruß,

Holm
OP #4750878
Lesenswert?

Ich habe den Zähler jetzt Initalisiert, laufen tut er aber viel zu 
schnell.
Normalerweise sollte das CNT Register ja jede Sekunde um +1 erhöht 
werden oder sehe ich das falsch?
Es wird aber viel zu schnell gezählt.

Hier meine Init ->
1
void RTC32_Init(void)
2
{
3
  /* Apply a reset of the VBAT */
4
  VBAT.CTRL |= VBAT_ACCEN_bm;
5

6
  /* Set access enable bit */
7
  VBAT.CTRL = VBAT_RESET_bm;
8

9
  /* Enable 32.768kHz crystal oscillator */
10
  VBAT.CTRL |= VBAT_XOSCEN_bm | VBAT_XOSCSEL_bm;
11

12
  /* Wait until oscillator is stable */
13
  while(!(VBAT.STATUS & VBAT_XOSCRDY_bm));
14

15
  /* Enable low power mode for external oscillator */
16
  OSC.XOSCCTRL = OSC_X32KLPM_bm;
17

18
  /* Reset RTC32 module */
19
  RTC32.CTRL = 0;
20
  
21
  /* Wait until sync done */
22
  while(RTC32_SyncBusy());
23

24
  /* Set PER to 1024. CLK source of the RTC32 is 1024 ticks / second = 1 Hz */
25
  RTC32.PER = 1023;
26

27
  /* Reset CNT register */
28
  RTC32.CNT = 0;
29

30
  /* Wait until sync done */
31
  while(RTC32_SyncBusy());
32

33
  /* Enable overflow interrupts */
34
  RTC32.INTCTRL = RTC32_OVFINTLVL_MED_gc;
35

36
  /* Enable real time module */
37
  RTC32.CTRL = RTC32_ENABLE_bm;
38

39
  /* Wait until sync done */
40
  while(RTC32_SyncBusy());
41

42
  /* Enable medium priority interrupts */
43
  PMIC.CTRL = PMIC_MEDLVLEN_bm;
44

45
  /* Enable global interrupts */
46
  sei();
47
}
Gast #4751165
Lesenswert?

1
void vbat_enable_xosc(bool use1khz)
2
{
3
        // Enable the failure detection.
4
        VBAT.CTRL |= VBAT_XOSCFDEN_bm;
5

6
        /* A delay is needed to give the voltage in the backup system some time
7
         * to stabilise.
8
         */
9
        delay_us(200);
10

11
        // Enable oscillator, with 1 kHz or 1 Hz output.
12
        if (use1khz)
13
                VBAT.CTRL |= VBAT_XOSCEN_bm | VBAT_XOSCSEL_bm;
14
        else
15
                VBAT.CTRL |= VBAT_XOSCEN_bm;
16
}

Gruß,

Holm
OP #4751991
Lesenswert?

Danke für deine Unterstützung.
Leider funktioniert das alles nicht so wirklich.
Habe jetzt die Init von der Atmel Note genommen...
Und von deinem letzten Post die VBAT Init. Diese führe ich direkt nach 
der Init von der RTC32 aus.

Wenn alles Konfiguriert ist, lese ich das CNT Register aus. Leider steht 
dort jedes mal "0".
1
int main (void)
2
{  
3
  system_clock_init();
4
  
5
  LCD_init();
6
    
7
  pwm_timer_init();
8
  
9
  PORTR.DIR |= (YELLOW_LED0_BIT  | YELLOW_LED1_BIT);
10
  PORTD.DIR |= (RED_STATE_LED_PIN | GREEN_POWER_LED_PIN);
11
  
12
  PORTE.DIRCLR = SWITCH_ONE_PIN;
13
  PORTF.DIRCLR = SWITCH_TWO_PIN;
14
  PORTF.DIRCLR = SWITCH_THREE_PIN;
15

16
  /* Reset the battery backup module */
17
  RTC32_Reset();
18

19
  /* Configure and enable TOSC, then set up and enable the RTC32 module */
20
  RTC32_ToscEnable(1);
21
  RTC32_Initialize(1023,0,0);
22

23
  /* Enable RTC compare interrupts */
24
  RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_LO_gc);
25

26
  PMIC.CTRL |= PMIC_LOLVLEN_bm;
27

28
  sprintf(Buffer,"%"PRIu32,RTC32_GetCount());
29
  LCD_SendString(Buffer,0,0);
30

31
  sei();
Gast #4752045
Lesenswert?

Jan H. schrieb:
> Danke für deine Unterstützung.
> Leider funktioniert das alles nicht so wirklich.
> Habe jetzt die Init von der Atmel Note genommen...

Was denn nun, vorher hattest Du den Zustand "viel zu schnell" was daran 
lag, das Du bei der Intialisierung nicht den 1 Sekunden Takt sondern den 
1Khz Takt ausgewählt hast.
1
VBAT.CTRL |= VBAT_XOSCEN_bm | VBAT_XOSCSEL_bm;

für 1Hz mußt Du aber
1
VBAT.CTRL |= VBAT_XOSCEN_bm;

benutzen.

..und nun zählt das Ding gar nicht mehr?

Du mußt Dir klar darüber werden wann Du die Uhr initialisieren willst, 
das sollte tunlichst nicht  bei jedem Systemstart sondern nur bei einem 
Reset passieren ansonsten haut es Dir die Zeit jedes Mal durcheinander.

> Und von deinem letzten Post die VBAT Init. Diese führe ich direkt nach
> der Init von der RTC32 aus.

Im Code der Application Note ist das so, das vbat_init() vor 
RTC32_Initialize() ausgeführt wird wenn ein Reset vorliegt, der 32Khz 
Oszillator mit Teiler muß erst einmal eingeschaltet werden.
Die Kontrolle über den Oszillator hat der vbat Modul.
Da ich keinen PowerOn Reset bei meiner Hardware hin bekomme ohne 3 
Stecker abzuziehen habe ich im Code einmalig vbat_init() beim startup 
gerufen und das so programmiert. Damit lief der Zähler dann los. Danach 
habe ichs wieder auskommentiert und wieder neu programmiert.

Gruß,
Holm
Gast #4752438
Lesenswert?

Jan H. schrieb:
> Sobald ich die Versorgungsspannung weg nehme, Resetet er den Zähler
> (CNT) und beim Starten fängt er wieder von "0" an. Ob ich es
> auskommentiere oder nicht.
>
> Kannst du mir mal deine Main zeigen?

...eigentlich nicht, ich werde dafür bezahlt das für Jemanden zu 
entwickeln, aber der Ausschnitt tuts vielleicht..das ist sowieso nur
der Appnote entsprechend:
1
int main(void)
2
{
3

4
uint8_t                                 vbat_status;
5
static  uint16_t                count;                                                  // Zaehler - zaehlt alle 10ms )
6
static  uint16_t                count_s;                                                // Zaehler - zaehlt jede sec )
7

8
        clock_init();
9
//      vbat_init();
10
        vbat_status = vbat_system_check(true);
11
        
12
        /* 
13
        * Depending on the VBAT system check appropriate actions need to 
14
        * be taken.
15
        * In this example we re-initialize the VBAT system in all
16
        * error cases.
17
        */
18
        switch (vbat_status)
19
        {
20
        case VBAT_STATUS_OK:
21
                // Interrupts must be re-enabled
22
                //RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_LO_gc);
23
                RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_OFF_gc);
24
                break;
25
        case VBAT_STATUS_NO_POWER: // fall through
26
        case VBAT_STATUS_BBPOR: // fall through
27
        case VBAT_STATUS_BBBOD: // fall through
28
        case VBAT_STATUS_XOSCFAIL: // fall through
29
        default:
30
                vbat_init();
31
                break;
32
        }
33
        port_init();
34
        adc_init();
35
        dac_init();
36
        usart_init();
37
//      spi_init();
38
#ifndef NO_RTC

90% davon hast Du schon mal gesehen..

Gruß,

Holm
Gast #4752486
Lesenswert?

grr...
1
//******************************************************************************
2
****************************************
3
void vbat_init(void)
4
{
5
        vbat_reset();
6
        vbat_enable_xosc(0);
7
        RTC32_Initialize(0xffffffff, 0, 0 );
8
        //RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_LO_gc);
9
        RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_OFF_gc);
10
}
11
//******************************************************************************

Wenn Du ihn jedesmal neu initialisierst brauchst Du Dich nicht wundern 
warum der immer von vorne anfängt zu zählen.

Gruß,

Holm
OP #4752496
Lesenswert?

Villeicht bin ich einfach nur zu Blöd dafür.
Er zeigt mir jedes mal nach nem Neustart "0" an!
1
int main (void)
2
{  
3
  sprintf(Buffer,"%"PRIu32,RTC32_GetCount());
4
  
5
  //vbat_init();
6
    switch (VBAT.STATUS)
7
    {
8
    case VBAT_STATUS_OK: RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_OFF_gc);break;
9
    case VBAT_STATUS_NO_POWER: // fall through
10
    case VBAT_STATUS_BBPOR: // fall through
11
    case VBAT_STATUS_BBBOD: // fall through
12
    case VBAT_STATUS_XOSCFAIL: // fall through
13
    default: vbat_init();break;
14
  }
15
  PMIC.CTRL |= PMIC_LOLVLEN_bm;
16
    
17
  sei();
18
  
19
  /* configure core clock */
20
  system_clock_init();
21
  
22
  /* configure lcd */
23
  LCD_init();
24
    
25
  /* configure pwm */
26
  pwm_timer_init();
27
  
28
  /* pins as output */
29
  PORTR.DIR |= (YELLOW_LED0_BIT  | YELLOW_LED1_BIT);
30
  PORTD.DIR |= (RED_STATE_LED_PIN | GREEN_POWER_LED_PIN);
31
  
32
  /* switch as input */
33
  PORTE.DIRCLR = SWITCH_ONE_PIN;
34
  PORTF.DIRCLR = SWITCH_TWO_PIN;
35
  PORTF.DIRCLR = SWITCH_THREE_PIN;
36

37
  /* interrupts enable */
38
  sei();
39
  
40
  sprintf(Buffer,"%"PRIu32,RTC32_GetCount());
41
  LCD_SendString(Buffer,0,0);
42
  _delay_ms(1500);
43
  
44
  while(1)
45
  {
46
    Board_TestMode();  
47
    sprintf(Buffer,"%"PRIu32,RTC32_GetCount());
48
    LCD_SendString(Buffer,0,0);
49
    _delay_ms(1500);    
50
  }
51

52
}
Gast #4752652
Lesenswert?

Offensichtlich ist bei dir der Status nicht VBAT_STATUS_OK.

Warum nimmst Du nicht mal den originalen und änderst ihn erst ab wenn er 
funktioniert hat? Hast Du die Brownout Detecor enable fuse gesetzt?

Was ist mit dieser Funktion?
1
uint8_t vbat_system_check(bool first_time_startup)
2
{
3
        uint8_t vbat_status;
4
        /*
5
         * Check if sufficient power was detected on the VBAT input. The brown-
6
         * out detector (BBBOD) will be sampled once when the device starts up
7
         * and the result is visible as the BBPWR flag.
8
         */
9
        if (VBAT.STATUS & VBAT_BBPWR_bm)
10
                vbat_status = VBAT_STATUS_NO_POWER;
11
        else {
12
                /*
13
                 * We hav sufficient power, now we check if a power-on-reset
14
                 * (BBPOR) was detected on VBAT. This is visible from the BBPORF
15
                 * flag which is also only updated once when the device starts.
16
                 */
17
                if (VBAT.STATUS & VBAT_BBPORF_bm) {
18
                        if (first_time_startup)
19
                                vbat_status = VBAT_STATUS_INIT;
20
                        else
21
                                vbat_status = VBAT_STATUS_BBPOR;
22
                }
23
                else if (VBAT.STATUS & VBAT_BBBORF_bm)
24
                        vbat_status = VBAT_STATUS_BBBOD;
25
                else {
26
                        VBAT.CTRL = VBAT_ACCEN_bm;
27
                        if (VBAT.STATUS & VBAT_XOSCFAIL_bm)
28
                                vbat_status = VBAT_STATUS_XOSCFAIL;
29
                        else
30
                                vbat_status = VBAT_STATUS_OK;
31
                }
32
        }
33
        return vbat_status;
34
}


Gruß,

Holm
Gast #4752839
Lesenswert?

Na also, geht doch.

Viel weiter bin ich auch noch nicht, aber die Zeit lät sich stellen mit 
mktime() und zum auslesen nehme ich gmtime()...2038 läuft allerdings 
dann der 23 Bit Timer über..
Ich bin dabei eine Software zu portieren die ich mal für den 
AtXmega128A3 geschrieben hatte und der hatte eine extern (PCFxxxx) Uhr 
on Board die nun wegrationalisiert wurde.
Ich habe noch genug an der Baustelle zu tun..die ADUs machen auch nicht 
ganz das was ich will..

Gruß,

Holm
Gast #4755028
Lesenswert?

..ist doch ausgeschaltet in vbat_init() :

         ....
        //RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_LO_gc);
        RTC32_SetCompareIntLevel(RTC32_COMPINTLVL_OFF_gc);
        ...
Ich brauchte keinen Interrupt, wollte nur zwecks Datenspeicherung auf SD 
Karte den aktuellen Timestamp abrufen können.
Den müßtest Du dort also wieder aktivieren, logischerweise reagiert die 
CPU auf den Interrupt aber nur im Sleepmode oder wenn sie wach ist, 
nicht wenn sie keinen Saft hat.

Gruß,

Holm
OP #4755102
Lesenswert?

Ja ist klar, habe ich schon gesehen.
Habe Versucht den Overflow Interrupt zu nehmen, bzw. einfach wie von dir 
gepostet (nicht CompareMatch) sondern eben Overflow.
Leider passiert da nichts.

Wie machst du das mit den Sekunden? Rufst du ständig das CNT Register ab 
und stellst den Wert da oder rufst du ihn einmalig beim App Start ab und 
lässt es dann via. Interrupt weiter zählen? Bzw. Wie würdest du das 
machen?
Gast #4755109
Lesenswert?

..der Overflow Interrupt löst bei Sekundentakt doch erst alle 168 Jahre 
aus (oder so..) Du mußt also noch ein Bisschen warten.

..es sei denn Du betriebst die Uhr wieder "zu schnell".


Ich brauche keine Echtzeit im Programm, es gibt da aber einen 
durchlaufenden 100ms Interrupt nach dem ich mich richte.
Beim Abspeichern von Datensätzen wird simpel der aktuelle Zeitstempel 
aus der RTC gelesen und dann verwendet.

Gruß,

Holm

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren