[winavr] _delay_ms dauert zu lange

Gast #827045
Lesenswert?

Ich hab mir dieses Ding gekauft: eStick 
http://www.technikum-wien.at/studien/bachelorstudien/elektronik/estick/
Das Ding wird von der FH Technikum Wien für wenig Geld am Tag der 
offenen Tür verkauft.

Das ist ein µC Starterkit mit einem at90usb162 der mit 8Mhz getaktet ist 
und per Flip über USB Programmiert wird.

Funktioniert auch wunderbar nur folgendes:

Wenn ich eine Schleife Programmiere die ein _delay_ms enthält zB:
1
  while(1)
2
  {
3
  PORTB = 0xFF;
4

5
    for(i=0;i<256;i++)
6
    {
7
      PORTB = ~i;  /* Wert an LED */
8
      _delay_ms(10);
9
   
10
    }
11
  }
Dann dauert ein Durchlauf der for-Schleife nicht 2,56 Sekunden sondern 
20,5 Sekunden. Exakt 8-mal solange wie eigentlich gewünscht.

Die Frequenzangabe im AVR-Studio ist mit 8000000 auch korrekt 
eingestellt und das Ding ist wirklich mit 8Mhz getaktet (oder zumindest 
ungefähr, habe es nur mit dem Oszi überprüft)

Man verzeihe mir meine blöde Frage: Was mache ich falsch?
Kann da noch irgendwo irgendwas falsch eingestellt sein?

Danke schon mal im Voraus
#827101
Lesenswert?

Man kann die Fuses auch ohne Programmer per Programm auslesen.
1
#ifndef SPMCSR
2
#define SPMCSR SPMCR
3
#endif
4

5
void fuses(void)
6
{
7
    SPMCSR = 1<<BLBSET | 1<<SPMEN;
8
    uint8_t lo = pgm_read_byte(0);
9
    SPMCSR = 1<<BLBSET | 1<<SPMEN;
10
    uint8_t hi = pgm_read_byte(3);
11
    PRINTF("Fuses: low=%02X high=%02X\n", lo, hi);
12
}
Obacht: Die exakte Code-Sequenz ist hier wichtig, die ersten 4 Zeilen 
der Funktion sollten also exakt so bleiben und Optimierung muss 
eingeschaltet sein. Getestet mit WinAVR 20070525 ATmega32.
Gast #827254
Lesenswert?

Der Controller hat 4 Fusebytes
1
void fuses(void)
2
{
3
    SPMCSR = 1<<BLBSET | 1<<SPMEN;
4
    uint8_t lo = pgm_read_byte(0);
5
    SPMCSR = 1<<BLBSET | 1<<SPMEN;
6
    uint8_t hi = pgm_read_byte(3);
7
//    PRINTF("Fuses: low=%02X high=%02X\n", lo, hi);
8
  PORTB = lo;
9
}

So komme ich IMO an das richtige Fusebit
(Wie das Wirklich funktioniert habe, ich gestehe, überhauptnicht 
verstanden)

Gesetzt = 0, ist mir klar!



Warnung hats nicht gegeben (ausgenommen, die nicht verwendete Variable 
"hi")

Optimierung hab ich im Avr-Studio unter "Project Options"
auf "-Os" gestellt(also nichts verändert). Ist das Richtig?
#827289
Lesenswert?

Christian M. wrote:

> (Wie das Wirklich funktioniert habe, ich gestehe, überhauptnicht
> verstanden)

Ist nichts anderes als das was im Datasheet steht (Boot Loader../Self 
Programming.../Reading the Fuse...). Die 2 Bits setzen und innerhalb von 
3 Takten das entsprechende Byte per LPM lesen.
#827675
Lesenswert?

Eine, möglicherweise blöde, Frage habe ich noch.

Kann die USB Funktion und der Bootloader funktionieren, wenn das CKDIV8 
fuse versehentlich gesetzt ist?

Spricht wäre es möglich, dass das Fuse-Bit falsch programmiert ist aber 
der  Controller trotzdem funktioniert nur langsamer?

danke, Christian
Gast #2802406
Lesenswert?

Andreas K. schrieb:
> Man kann die Fuses auch ohne Programmer per Programm auslesen.

Geht das auch umgekehrt? Kann ich über die Software die Fuses setzen?
In einem Programm habe ich folgendes gefunden:

FUSES =
{
   .low      = 0xFF,
   .high     = 0xD9,
   .extended = 0xFD,
};

Kann mir hier jemand diesbezüglich weiterhelfen?
Gast #2802681
Lesenswert?

Für den AT90USB162 sollte das auch gehen:
1
// 8 MHz
2
CLKPR &= ~((1 << CLKPS3) | (1 << CLKPS2) | (1 << CLKPS1) | (1 << CLKPS0));
3

4
// 1 MHz
5
CLKPR &= ~((1 << CLKPS3) | (1 << CLKPS2));
6
CLKPR |=   (1 << CLKPS1) | (1 << CLKPS0);
Gast #2802685
Lesenswert?

Hi

>Soweit ich weiss kann man die CKDIV8 fuse auch aus dem Programm heraus
>setzen. Beim Atmega32u4 zum Beispiel über das CLKPR – Clock Prescaler
>Register.

Ein gesetzte CKDIV8-Fuse bewirkt, das CLKPR nach einem Reset auf einen 
Teiler von acht gesetzt wird. Das Überschreiben von CLKPR hat aber 
keinen Einfluss auf die CKDIV8-Fuse.

MfG Spess
Gast #2802694
Lesenswert?

spess53 schrieb:
> Hi
>
>>Soweit ich weiss kann man die CKDIV8 fuse auch aus dem Programm heraus
>>setzen. Beim Atmega32u4 zum Beispiel über das CLKPR – Clock Prescaler
>>Register.
>
> Ein gesetzte CKDIV8-Fuse bewirkt, das CLKPR nach einem Reset auf einen
> Teiler von acht gesetzt wird. Das Überschreiben von CLKPR hat aber
> keinen Einfluss auf die CKDIV8-Fuse.
>
> MfG Spess

Das stimmt natürlich, da hab ich mich sehr schlecht ausgedrückt.

Was ich eigentlich sagen wollte, ist das dies für den OP ein einfacher 
workaround ist, wenn er Programme mit 8MHz ausführen will.
#2802710
Lesenswert?

Verwirrter Anfänger schrieb:
> Was ich eigentlich sagen wollte, ist das dies für den OP ein einfacher
> workaround ist, wenn er Programme mit 8MHz ausführen will.

Um den OP geht es aber gar nicht mehr (mal auf das Datum geschaut?).
Es geht momentan um
> Andreas K. schrieb:
>> Man kann die Fuses auch ohne Programmer per Programm auslesen.
>
> Geht das auch umgekehrt? Kann ich über die Software die Fuses setzen?
Und da lautet die Antwort ganz simpel: Nein.
#4952717
Lesenswert?

Christian M. schrieb:
> Der Controller hat 4 Fusebytes
> void fuses(void)
> {
>     SPMCSR = 1<<BLBSET | 1<<SPMEN;
>     uint8_t lo = pgm_read_byte(0);
>     SPMCSR = 1<<BLBSET | 1<<SPMEN;
>     uint8_t hi = pgm_read_byte(3);
> //    PRINTF("Fuses: low=%02X high=%02X\n", lo, hi);
>   PORTB = lo;
> }


Andreas K. schrieb:
> Man kann die Fuses auch ohne Programmer per Programm auslesen.
> #ifndef SPMCSR
> #define SPMCSR SPMCR
> #endif
>
> void fuses(void)
> {
>     SPMCSR = 1<<BLBSET | 1<<SPMEN;
>     uint8_t lo = pgm_read_byte(0);
>     SPMCSR = 1<<BLBSET | 1<<SPMEN;
>     uint8_t hi = pgm_read_byte(3);
>     PRINTF("Fuses: low=%02X high=%02X\n", lo, hi);
> }

Sorry fürs Leichenfleddern, aber da der Thread hier im Wiki verlinkt 
ist, muss ich mich doch zu Wort melden. Man kann mittlerweile die Fuses 
und die Lock-Bits so hier auslesen:
1
#include <avr/boot.h>
2

3
int main()
4
{
5
    uint8_t lf = boot_lock_fuse_bits_get(GET_LOW_FUSE_BITS);
6
    uint8_t hf = boot_lock_fuse_bits_get(GET_HIGH_FUSE_BITS);
7
    uint8_t ef = boot_lock_fuse_bits_get(GET_EXTENDED_FUSE_BITS);
8
    uint8_t lk = boot_lock_fuse_bits_get(GET_LOCK_BITS);
9
}

Grüße
Oliver

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