Programmazione CLKPR

Ciao!
Sto provando da poco la programmazione tramite tramite Atmel Studio 6 e mi son voluto imbattere nella programmazione, per prova, dei registri del prescaler.
C'è tanta documentazione, datasheet incluso, che spiega come farlo. E l'ho fatto. E' uno stile simile al Freescale, dal quale provengo diciamo, ma comunque come tutti i micro anche senza bootloader.
Dopo aver realizzato che i fuses non li posso cambiare se non riscrivo il bootloader ho fatto una cosa: togglo il led della scheda con un for, se cambio il prescaler deve cambiare pure quello. E invece no. Come mai?

# define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>


int main(void)
{
	
	CLKPR=_BV(CLKPCE);
	CLKPR=(CLKPR & (~_BV(CLKPS0) | ~_BV(CLKPS1) | ~_BV(CLKPS2) | _BV(CLKPS3)));
	DDRB=0x20;
	unsigned int i;
    while(1)
    {
	for(i=0; i<65000; i++);
	for(i=0; i<65000; i++);
	for(i=0; i<65000; i++);
	for(i=0; i<65000; i++);
     //_delay_ms(1000); era per un prova per vedere che usasse davvero i 16Mhz, forse è compensato dal prescaler dnque son passato ai for
	 PINB=0x20;
    }
}

Grazie a tutti anticipatamente!

Circa il prescaler non so risponderti, dovrei leggere il datasheet del micro.

Riguardo al resto del codice posso dirti la seguente:

Nel commento fai riferimento al fatto che toggli un pin di una porta, cioè assegni al pin il valore attuale ma invertito, detto in altri termini fai il flip di un bit di una porta.

Però io il codice che fa il flip non lo vedo.

// imposta un pin di una porta come OUTPUT
PORT? |= _BV(nbit);   // sostituisci il ? con la lettera della porta, sostituisci nbit con il nome del pin.
// es. imposta il pin PB0 (dal datasheet) della porta B come output

PORTB |= _BV(PB0);

// flip bit 0 di porta B, cioè quando viene eseguito se il valore corrente è 0 diverrà 1, accade l'inverso  prossimo cilco 
PORTB ^= _BV(PB0);

Su quei for vuoti ho il dubbio che il compilatore li compili, credo che li salti del tutto, per evitare di saltarli
inserisci una direttiva asm nop

for (.....
    asm volatile("nop\n\t"::);

Ciao.

No no il toggle lo fa. E' riguardo i timing il problema.
Per il resto bo, io ho cominciato a studiarlo seriamente dal datasheet. Scrivendo 1 al bit #x del PINB register della porta Bx viene invertito il suo valore ad ogni nuova scrittura, in pratica è come l'equivalente di una XOR con un latch sul bit. :slight_smile:

Hai raggione il pin toggle funziona, e io non lo sapevo perchè non ho letto quanto è scritto nel datasheet:

Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn.
Note that the SBI instruction can be used to toggle one single bit in a port.

Mentre per il prescaler dice che per evitare di cambiare il valore accidentalmente c'è da fare una procedura.

Imposta il bit CLKPCE a 1 e poi entro 4 cicli di clock applica il valore del prescaler voluto al registro CLKPR impostando il bit CLKPCE a 0.

Dal datasheet:

To avoid unintentional changes of clock frequency, a special write procedure must be followed
to change the CLKPS bits:

  1. Write the Clock Prescaler Change Enable (CLKPCE) bit to one and all other bits in
    CLKPR to zero.
  2. Within four cycles, write the desired value to CLKPS while writing a zero to CLKPCE.
    Interrupts must be disabled when changing prescaler setting to make sure the write procedure is
    not interrupted.

Mi dici su quale micro stai lavorando? così almeno guardiamo lo stesso datasheet.

_delay_ms e us dovrebbero funzionare, non c'è motivo che non funzionino, tra l'altro la versione 6 dovrebbe lavorare con la toolchain 4.5.1 è il delay è costruito su un funzione built-in del compilatore.

PS: nel codice che ho postato c'è un errore, al posto di PORT? ci va DDR?, ora lo correggo.

Ciao.

Atmega 328p. Scusa.
Ho risolto per il prescaler: CLKPR=8 e tutto si risolve perché chiede meno di 4 cicli :smiley:

Le funzioni vanno bene, ma lo sto facendo per capire il micro con approccio in C puro, non oggetti in C++ e senza librerie Arduino.

thexeno:
Atmega 328p. Scusa.
Ho risolto per il prescaler: CLKPR=8 e tutto si risolve perché chiede meno di 4 cicli :smiley:

Le funzioni vanno bene, ma lo sto facendo per capire il micro con approccio in C puro, non oggetti in C++ e senza librerie Arduino.

Ottimo, se posti il codice funzionante magari c'è qualcuno che vuole seguire la stessa strada e si fa esperienza insieme.

Ciao.

A be, per come impostare l'IDE per programmare con l'avrdude è pienissimo di guide. Per il codice, quel CLKPR=8 l'ho sostituito a tutto quel CLKPR seguito da quelle OR che settano bit per bit. IL tutto dopo CLKPR=_BV(CLKPCE); ovviamente. :slight_smile: