Scalare la frequenza di clock a run-time

Ho sperimentato tramite il simulatore wokwi la possibilità di scalare la frequenza di clock di arduino nano (ATmega328). In effetti scala almeno fino al divisore x64, cioè 16MHz / 64. Oltre la IRREMOTE non ha sufficiente clock per lavorare (credo). La cosa interessante almeno con il simulatore che non è necessario riconfigurare la seriale.

Ne è nata la seguente piccola funzione:

void divideClockSystem(uint16_t div) {
    if (div > 256)
        div = 256;
    div = log(div) * M_LOG2E;
    Serial.println(div);
    cli();  // disabilita gli interrupt 
    CLKPR = _BV(CLKPCE);
    CLKPR = (uint8_t)div;
    sei(); // enable global interrupt
}

Da chiamare con:

divideClockSystem(div); // div 1,2,4,8,16,32,64,128,256

PS:c'era un post di un utente che chiedeva come ridurre il consumo di un
allarme fatto con arduino, direi che questa funzione può tornare utile per ridurre il consumo con o senza sleep mode.

Ciao.

Abbiamo già molte volte affrontato il problema e fornito una soluzione che modifica il clock anche prima che si avvi il .ino :wink:

E NO, nella realtà, ovviamente, la velocità della seriale È influenzata dal clock che imposti e quindi ne risente ... :roll_eyes:

Guglielmo

Credo invece che la seriale lavori sempre con il clock fornito dal quarzo, cioè 16MHz, mentre timer ecc vengono influenzati. Sembra anche così leggendo il datasheet, che dice:

9.11
System Clock Prescaler
The ATmega48A/PA/88A/PA/168A/PA/328/P has a system clock prescaler, and the system clock can be
divided by setting the ”CLKPR – Clock Prescale Register” on page 46. This feature can be used to decrease the
system clock frequency and the power consumption when the requirement for processing power is low. This can
be used with all clock source options, and it will affect the clock frequency of the CPU and all synchronous
peripherals. clk I/O , clk ADC , clk CPU , and clk FLASH are divided by a factor as shown in Table 29-11 on page 314.

Mah ... non mi sembra a giudicare dallo schema interno del flusso del clock ...

Guglielmo

P.S.: ... ed anche leggendo il capitolo relativo alla USART :roll_eyes:

Ma infatti sto cercando di capire la differenza tra asincrono e sincrono, la USART la usiamo in modo Asincrono, vorrei capire da dove prende il clock.
In ogni caso basta provare sull'hardware e verificare cosa succede alla seriale. Con RP2040 devo riconfigurare la seriale quando cambio il clock.

Da clock distribution sembra che il prescaler influenzi tutto.

Nel pomeriggio mi procuro una nano.
Ciao.

Forse anziché due logaritmi, funzioni analogiche, sarebbe meglio fare i calcoli logicamente:

void divideClockSystem(uint16_t div)
{
if(div==0 || div>256 || (div & (div-1))!=0) // Verifica che div stia fra 1 e 256
                                            // e che abbia un solo bit a 1.
// Oppure: 
// if(div==0 || div>256 || __builtin_popcount(div)>1)
  {
  Serial.println("Valore errato!");
  return;
  }

uint8_t n=0;
while(div>=2)
  {
  div>>=1; // Grazie, Maurotec!
  n+=1;
  }
// Oppure:
// uint8_t n=__builtin_ctz(div);

Serial.println(n);
cli();  // Disabilita gli interrupt.
CLKPR=_BV(CLKPCE);
CLKPR=n;
sei(); // Riabilita gli interrupt.
}

Ottimo, correggi solo div >>= 1, per il resto
butta via questa sintassi artistica priva di utilità pratica. :smiley:

Ora esco e mi procuro una nano.

Ciao.

div>>=1? Dove l'ho scritto?...
Ah! Devo correggere div>>1 in div>>=1, come se fosse x+=1!
E' vero! Adesso ho capito. Mi sto arrugginendo un po'...
Grazie!

Non so se ti stai arrugginendo, anzi io penso proprio di no, ciò che ti rovina è la sintassi: div spazio 3 caratteri per l'operatore >>= e uno spazio a cui segue l'operando. Lo si vede a colpo d'occhio che non sono tre caratteri per cui qualcuno mi deve essere rimasto nella tastiera.

Ora dammi un buon motivo per usare la tua sintassi tutto attaccato senza spazi, perché io ci trovo solo svantaggi. :smiling_face_with_sunglasses:

PS: non avevano la nano, ma la 2560 mini a 15€, ovviamente gliel'ho lasciata. :grinning_face_with_smiling_eyes:
Ciao.

Intanto, giusto per dare un po' di teoria ...
... premesso che il registro che ci interessaè il seguente:

... e che i valori che può assumere sono nella segunte tabella (valori oltre il 256 NON sono validi e sono riservati):

Se abbiamo la necessità di avviare la nostra scheda (basata su ATmega328P) con un clock sottomultiplo del clock che abbiamo, possiamo inserire, in testa al nostro programma, il seguente codice (i valori riportati nel codice sono per un prescaler che divide per 2 ... comodo per portare il classico clock da 16 MHz a 8MHz così da poter far funzionare, in sicurezza, la MCU a 3.3v):

void set_Clock(void) __attribute__((naked)) __attribute__((section(".init3"))) __attribute__((used));

void set_Clock(void) {
 cli();
 CLKPR = (1 << CLKPCE) | (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); // Enable change
 CLKPR = (0 << CLKPCE) | (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (1 << CLKPS0); // Prescaler 2
 sei(); 
}

La funzione NON deve essere richiamata ... viene automaticamente messa in esecuzione PRIMA del main() e delle chiamate a setup() e loop(), facendoci quindi trovare, all'avvio del nostro programma, il clock già impostato come vogliamo. :slight_smile:

Guglielmo

Ah, per chi fosse interessato ad approfondire, il significato delle "section" in cui si può definire che un codice vada, è documentato QUI ed in particolare, quella utilizzata (.init3) la si trova dove parla delle "The .initN Sections".

Per completezza, le funzioni contrassegnate con __attribute__((used)) sono contrassegnate nel file oggetto per evitare la rimozione della sezione (che può apparire inutilizzata) da parte del linker. :wink:

Guglielmo

Interessante

Vuoi metterlo nella nostra: "la pappa è fatta"?

O magari si crea una sezione "suggerimenti e trucchi?"
(Tip and tricks in italiano)

... o linkarlo in "Aiutateci ad Aiutarvi" ??? :slightly_smiling_face:

Guglielmo

Questa discussione mi ha portato a scoprire popcount e ctz, che ho inserito come opzioni nel programmino precedente. Possono sempre essere utili...

Posto che come decidi tu per me è sempre un onore

Però aiutateci ad aiutarvi mi sembra più per cose "propedeutiche"

Mentre per "soluzioni chiavi in mano" vedo più la pappa...

Magari per cose meno complete, diciamo appunto trucchi e suggerimenti sto pensando a un:
"Il biliardino delle idee"

Dove mettere appunto ritagli di programmi che siano ispirazione

Adesso sto pensando alla "programmazione a oggetti" in C
Da un'idea che ho avuto leggendo il Dinamico Duo, la macchina a stati finiti

Se mi esce...

... allora vada per "la pappa" :wink:

... non ricordo dove (se lo trovo te lo segnalo), ma ricordo un bel articolo sull'argomento ... :thinking:

Comunque cercado su Google "c programming language object oriented" ... si trova un bel po' di materiale ... :roll_eyes:

Guglielmo