#define da registri Hardware

di il
10 risposte

#define da registri Hardware

Ciao a tutti!
Ho il seguente problema:
ho un file di configurazione dove ci sono diverse #define che vengono usate per inizializzare delle strutture nel codice.
Attualmente queste #define sono scritte in un header ma si vuole implementare la seguente dinamica: il valore delle define viene letto da dei registri di una memoria esterna di cui sono noti gli address, cosi che se cambia l'hardware, anzichè modificare a mano tutte le #define e ricompilare, si cambia la memoria mantenedo gli address e il codice ha a disposizione i nuovi valori.
La soluzione più semplice sarebbe cambiare le #define direttamente con gli accessi agli address, faccio un esempio:

#define VAR 10

diventa

#define VAR  *(uint32_t *)0xA000

ma ho paura che così facendo, se la memoria è lenta, il codice rallenta perchè ogni #define diventa un accesso a memoria esterna. Vi chiedo se conoscete altri modi per risolvere il problema.


Grazie a chi mi aiuterà.

10 Risposte

  • Re: #define da registri Hardware

    Intanto suppongo che si parli di C, anche se non lo dici.

    Per la questione che poni, all'inizio del programma devi semplicemente leggere il valore da quel registro in una variabile e poi usare la variabile ovunque ti serva.

    Così avrai fatto una sola lettura e il valore lo avrai a disposizione.

  • Re: #define da registri Hardware

    Ciao!
    Grazie per la risposta.

    Hai ragione, perdonami, parliamo di codice C.

    Avevo pensato di fare una routine in fase di init dove poter leggere la memoria e inizializzare tutte le strutture che usano quelle #define ma questo pesa sulle prestazioni, per cui l'idea era di cercare un modo per risolvere in tutto in fase di compilazione.

    Attualmente ho raggruppato alcune delle #define in un modulo SW dove ho una struttura globale const.
    Questa struttura viene mappata direttamente su memoria, oppure, se siamo in fase di debug, con uno switch di compliazione, viene inizializzata direttamente da codice.
    Tuttavia alcune di queste #define vengono utilizzate a loro volta per inizializzare, sempre in fase di compilazione, altre strutture, per cui in questo caso il compilatore va in errore “inizializer element is not cost” quando cerca di valorizzare le altre strutture.

    Sto cercado di capire se ci sono altre vie per risolvere tutto in fase di compilazione ma per ora non trovo soluzioni.

  • Re: #define da registri Hardware

    Non capisco ancora il problema, non vedendo codice è ancora peggio.

    Quando compili non puoi certamente eseguire codice.

  • Re: #define da registri Hardware

    @ILDAV, stai facendo un ‘pasticcio’! 

    Il compilatore COMPILA, se sei fortunato calcola anche espressioni COSTANTI, se sei ancora piu' fortunato e' in grado di chiamare funzioni a cui vengono passati valori COSTANTI e quindi, OVVIAMENTE, ritornano un valore COSTANTE. 

    Per  lui, una locazione di memoria E' PER SUA NATURA un posto che puo' cambiare valore QUINDI non puo' risolvere il contenuto dell'indirizzo di memoria come se fosse una costante!

    Ma ANCHE se fosse possibile, da quanto dici, ogni hardware contiene in quell'indirizzo di memoria un valore diverso. Quindi dovresti compilare il software su OGNI Hardware invece di compilarlo una sola volta e distribuirlo. 

    INSOMMA, quello che vorresti fare NON HA SENSO. 

    NON SE PO' FA!

    Il problema delle prestazioni non e' certamente nella lettura della locazione di memoria fatta UNA SINGOLA VOLTA. I ‘pasticci' sono altri. 

  • Re: #define da registri Hardware

    Ciao a tutti.

    Forse mi sono spiegato male.

    Il codice purtroppo non lo posso condividere ma provo a fare degli esempi.

    Attualmente il codice ha un file di configurazione “conf.h” dove ci sono tutte queste #define che vengono poi usate in più parti del codice, sia livello funzionale, nelle espessioni, nei confronti, ma anche per inizializzare altre strutture del tipo:

    tx =
    {
        .param_1 = DEFINE_1
        .param_2 = DEFINE_2
    }

    Strutture che si trovano in dei file sorgenti .c che includono l'attuale “conf.h” 

    Ora si vule che queste #define derivino da una memoria esterna in caso di software rilasciato, mentre nel sw di debug i valori devono rimanere modificabili a mano da codice. Per cui il SW di rilascio deve prendere questi valori da una memoria i cui indirizzi sono noti e sono sempre quelli.
    Come dicevo prima, la soluzione di trasformare, per sempio:

    
    #define DEFINE_1 10

    in

    
    #define DEFINE_1 *(uint32_t *)0xA000

    aggiungendo uno switch di compilazione per selezionare la configurazione di debug da quella di rilascio, funziona perfettamente, ma non ha convinto. Sul motivo posso solo aggiungere che le decisioni non le prendo io. Stessa storia per la routine in fase di inizializzazione: funziona perfettamente, ma le decisioni non le prendo io.

    L'unica soluzione che ho trovato è stata quella di creare un conf.c che insieme al conf.h forma un nuovo modulo SW dove ho, per esempio:

    
    typedef struct =
    {
        uint32_t DEFINE_1
        uint32_t DEFINE_2
    } conf_t;
    


    nel .h e nel .c ho la globale:

    
    const  conf_t Gv_conf;

    che se siamo in SW di rilascio, viene mappata con l'indirizzo della memoria (anche questo metodo funziona), mentre in caso contrario, con uno switch, ho la struttura inzializzata sul codice, per esempio:

    
    Gv_conf = { .DEFINE_1 = 10, .DEFINE_2 = 11 };


    questo ovviamente implica che il codice va modificato ovunque vengano usate le #define.
    In questo caso il codice funziona, ad eccezione di quelle #define che a loro volta inizializzano strutture del tipo:

    
    tx =
    {
        .param_1 = DEFINE_1
        .param_2 = DEFINE_2
    }

    Per queste giustamente il compilatore mi fa una pernacchina.
    Quindi stavo cercando una soluzione che potesse funzionare per tutto.

    Mi spiace non poter condividere di più, ma spero sia più chiaro.

    Grazie

  • Re: #define da registri Hardware

    E a me dispiace non aver compreso ancora il tuo problema.

    Chiariamo un punto. Nelle #define si definiscono stringhe che sono sostituite nel codice e valutate solo durante la compilazione.

    Quindi, quello che ti resta da fare è usare una funzione di Inizializzazione che venga richiamata all'inizio del programma quando questo viene eseguito e che imposti i valori corretti.

    Se inizializzi i campi di strutture con delle costanti, ovviamente avrai sempre quei valori. Devi fare in modo che la funzione (o le funzioni di inizializzazione) restituiscano le strutture a runtime create con i valori corretti. Ma ci voglio delle funzioni che vengono eseguite, non puoi farlo al momento della compilazione.

  • Re: #define da registri Hardware

    In realtà mi hai dato la risposta.
    Cercavo di capire se c'era un modo risolvere tutta questa situazione a tempo di compilazione, ma da quello che dici semplicemente non si può.
    Grazie mille.

  • Re: #define da registri Hardware

    Come si suo dire: 

    non si puo' cavare sangue da una rapa!

    non si cava un ragno dal buco!

    Se non si puo' fare, NON SI PUO' FARE!

    #define DEFINE_1 10

    il PRECOMPILATORE sostituisce la STRINGA “DEFINE_1” CON LA STRINGA “10”, e genera il file intermedio scritto TOTALMENTE IN C, che poi il compilatore compila.

    #define DEFINE_1 *(uint32_t *)0xA000

    il PRECOMPILATORE sostituisce la STRINGA “DEFINE_1” CON LA STRINGA “*(uint32_t *)0xA000”, e genera il file intermedio scritto TOTALMENTE IN C, che poi il compilatore compila.

    E non c'e' NULLA che si possa fare in modo diverso.

    Usando SOLO il C/C++, potresti scrivere

    constexpr uint32_t DEFINE_1=10;

    e questo FUNZIONA perche NON E' il PREPROCESSORE che fa il lavoro, ma lo fa il COMPILATORE che SA che puo' sostituire il SIMBOLO “DEFINE_1” con l'INTERO COSTANTE “10”

    Questo, invece

    constexpr uint32_t DEFINE_2=*(uint32_t*)(0xA000);
    main3.cpp:20:34: error: 'reinterpret_cast<uint32_t* {aka unsigned int*}>(40960)' is not a constant expression
       20 |     constexpr uint32_t DEFINE_2=*(uint32_t*)(0xA000);
          |                                  ^~~~~~~~~~~~~~~~~~~

    NON PUO' FUNZIONARE. E NON C'E' NULLA che si possa fare.

    C'e' una differenza tra “const”e “constexpr”: le “constexpr” sono espressioni COSTANTI che il compilatore POTREBBE ottimizzare GIA' DURANTE la compilazione, se e' abbastanza “intelligente”. Mentre “const” e' una “variabile” che puo' essere assegnata una sola volta e non puo' piu' essere riassegnata, e questo controllo lo fa il compilatore. Ma non fa nessun “ragionamento” su come viene calcolato il valore da assegnare.

    Puoi sempre dire ai tuoi capi: visto che guadagnate piu' di me, ditemi voi come fare ;-)
    In alternativa, se volete che trovi come fare, datemi l'aumento ;-) ;-)
    Altrimenti: 

    mangiate questa minestra o saltate dalla finestra

    ;-)

  • Re: #define da registri Hardware

    06/03/2024 - migliorabile ha scritto:


    Come si suo dire: 

    non si puo' cavare sangue da una rapa!

    non si cava un ragno dal buco!

    Se non si puo' fare, NON SI PUO' FARE!

    #define DEFINE_1 10

    il PRECOMPILATORE sostituisce la STRINGA “DEFINE_1” CON LA STRINGA “10”, e genera il file intermedio scritto TOTALMENTE IN C, che poi il compilatore compila.

    #define DEFINE_1 *(uint32_t *)0xA000

    il PRECOMPILATORE sostituisce la STRINGA “DEFINE_1” CON LA STRINGA “*(uint32_t *)0xA000”, e genera il file intermedio scritto TOTALMENTE IN C, che poi il compilatore compila.

    E non c'e' NULLA che si possa fare in modo diverso.

    Usando SOLO il C/C++, potresti scrivere

    constexpr uint32_t DEFINE_1=10;

    e questo FUNZIONA perche NON E' il PREPROCESSORE che fa il lavoro, ma lo fa il COMPILATORE che SA che puo' sostituire il SIMBOLO “DEFINE_1” con l'INTERO COSTANTE “10”

    Questo, invece

    constexpr uint32_t DEFINE_2=*(uint32_t*)(0xA000);
    main3.cpp:20:34: error: 'reinterpret_cast<uint32_t* {aka unsigned int*}>(40960)' is not a constant expression
       20 |     constexpr uint32_t DEFINE_2=*(uint32_t*)(0xA000);
          |                                  ^~~~~~~~~~~~~~~~~~~

    NON PUO' FUNZIONARE. E NON C'E' NULLA che si possa fare.

    Puoi sempre dire ai tuoi capi: visto che guadagnate piu' di me, ditemi voi come fare ;-)
    In alternativa, se volete che trovi come fare, datemi l'aumento ;-) ;-)
    Altrimenti: 

    mangiate questa minestra o saltate dalla finestra

    ;-)

    ahahah proverò a seguire il tuo consiglio!
    grazie mille anche a te

  • Re: #define da registri Hardware

    Ma scusa, come fa a pesare sulle prestazioni una routine in fase di init? Una volta che sei nel loop principale del programma che ti frega? Quello che dice Oregon è la soluzione che usano tutti

    Che poi è da vedere se la *(type *) rallenta davvero tutto. Dipende dall'architettura 

Devi accedere o registrarti per scrivere nel forum
10 risposte