Rimappare le periferiche sui pic a 16bit (dsPic/PIC24). La funzione Peripheral Pin Select (PPS)

Giovanni Bernardo | 8 settembre 2010
Categorie: dsPIC / PIC24

Ho cominciato da poco a cimentarmi con i dsPic e ho deciso quindi di  pubblicare, come mio solito, degli appunti ad ogni step, in maniera tale che possano essere d’aiuto a chi vuole cominciare ad entrare in questo nuovo mondo. Lo scopo è come sempre anche quello di creare un  nuovo argomento di discussione in maniera tale da far entrare in gioco i più esperti e non di modo che si possano condividere conoscenze ed esperienze.

Questo e quelli che seguiranno, quindi, non vorranno essere delle vere e proprie lezioni di programmazione dei dsPic, ma degli appunti personali, scritti da una persona che dai pic 10/12/16/18 vuole passare ai pic a 16 bit. Lavorando con i pic ad 8 bit è normale che prima o poi venga la voglia di fare il “salto di qualità” verso qualcosa di più complesso o solo per la voglia di imparare, quindi le mie esperienze saranno più rivolte verso chi già sa programmare i pic ad 8 bit in quanto mi limiterò ad analizzare le differenze.

Abituato con i pic ad 8 bit devo dire che è “quasi” tutto un’altro mondo. Le differenze rispetto ai pic ad 8 bit sono davvero parecchie:  la complessità e il numero di periferiche a disposizione,  l’elevato numero di impostazioni e settaggi per utilizzarli e alcune piccole cose a livello di programmazione. Ma la sostanza in effetti non cambia: programmiamo sempre in C anche se per i pic a 16bit (ovvero dsPic30, dsPic33, pic24F, pic24H) si utilizzerà il C30, sempre disponibile gratuitamente per il download in versione student edition (links nella pagina PicMicro).

Cominiciamo quindi con una delle prime caratteristiche salienti: la funzione Peripheral Pin Select.

C’è una periferica qua e devo metterla là

Molti pic a 16bit hanno questa interessante funzione che permette di piazzare fisicamente una determinata periferica sul pin che vogliamo (non tutte le periferiche, per carità, alcune difatti hanno un’assegnazione fissa come siamo già abituati). Questa funzione è davvero molto comoda perchè in fase di progetto non saremo più vincolati ad utilizzare dei pin prefissati ma possiamo scegliere, ad esempio, l’UART su quali pin deve stare, così come tante altre periferiche. Tale funzione ci permette addirittura di multiplexare su un unico pin anche più di una periferica!

Prendiamo un dsPic di esempio, pensato per scopi generici (GP : General Purpose. I dsPic, difatti, sono classificati in base allo “scopo” per il quale sono stati creati: controllo motori, processori digitali audio ecc): il dsPIC 33FJ128GP802. Tale dsPic ha addirittura due periferiche UART ed è con queste che farò l’esempio.

Andiamo quindi a vedere come sempre il datasheet per capire dove sono posizionati i pin Rx e Tx di queste due periferiche:

A parte il fatto che, come vedete, ogni pin ha una miriade di funzioni, all’inizio si rimane spaesati pensando al fatto che questo dsPic ha 2 periferiche UART ma sul pinout dell’integrato non ci sono i pin destinati ad esse! Ma la cosa bella è che nel datasheet non c’è scritto nulla al riguardo della  apparente “scomparsa” di questi due pin !

In realtà la soluzione a questo mistero  è un po’ più macchinosa da cercare rispetto a come siamo abituati normalmente. Data l’enorme complessità delle periferiche presenti sui dsPic, la Microchip ha pensato, giustamente, di non riscrivere tutto il malloppo di informazioni per ogni dsPic sul proprio datasheet, ma di organizzare le informazioni comuni a tutti in una pagina apposita:

http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2573

In questa pagina sono raggruppati, in pdf separati, i vari capitoli del dsPic33F Family Reference Manual.

Dopo tutto quello che vi ho detto all’inizio, potete capire quindi che l’UART su questo dsPic non ha un’assegnazione di default: ovvero al reset l’UART “non ha sbocchi”, dovremo essere noi, da codice, a dire al Pic quali pin utilizzare per l’UART (UART1 o UART2 o entrambe).

Il documento di riferimento per la selezione dei pin per le periferiche è quello indicato appunto come I/O Ports with Peripheral Pin Select. In questo caso poi, specifico dell’UART,  per i settaggi dovremo andarci a leggere anche il capitolo relativo all’UART (difatti sui dsPIC abbiamo una UART coi fiocchi: non ci sono solo Rx e Tx ma anche i pin per il controllo di flusso e tante altre caratteristiche aggiuntive), ma di questo non ci occuperemo in questo articolo.

Prima di iniziare chiariamo innanzitutto alcuni punti:

  • I pin sui quali si possono rimappare le periferiche sono contrassegnati con RPn. Vedete che nel datasheet del dsPic preso ad esempio, i pin RPn sono associati ai pin RBn.
  • Le periferiche che possono essere rimappate sono solo quelle digitali. Le funzioni analogiche quindi hanno sempre un’assegnazione dei pin fissa.
  • Sebbene il remapping delle periferiche è destinato solo a quelle digitali, alcune di esse hanno assegnazione fissa e non possono essere rimappate perchè richiedono una circuiteria speciale. L’I2C è una di queste.
  • Le periferiche che hanno la possibilità di essere rimappate, non hanno mai nessun pin assegnato di default, ecco perchè, ad esempio, l’UART o l’SPI non appaiono sul pinout.

Periferica di Input e periferica di Output

La modalità con cui una periferica viene associata ad un pin è diversa a seconda che la funzione associata sia una funzione di input o di output. Per le funzioni di input viene assegnata la periferica al pin (il remapping viene effettuato sulla base della periferica), per le funzioni di output viene assegnato il pin alla periferica (remapping effettuato sulla base del pin).  Prima che andiate nel pallone vediamo cosa vuol dire tutto questo prendendo ad esempio proprio l’UART che ha sia funzioni di input (RX) che di output (TX).

Nel caso della funzione di input, abbiamo detto che prendiamo come base la periferica e quindi tra tutti i pin disponibili ne scegliamo uno e lo associamo alla periferica, che in questo caso è la UART1-RX (trattiamo la funzione di ricezione della UART come se fosse una periferica a sè stante):

Come vedete, sulla sinistra abbiamo i vari pin RPn, che sono quelli disponibili per il remapping, e sulla destra abbiamo la periferica U1RX (UART1 – funzione di ricezione RX). Possiamo scegliere uno qualsiasi dei pin ed associarlo quindi alla periferica.

La funzione di remapping per i pin di input viene effettuata tramite i registri RPINRx (dove x è un numero variabile). Ognuno di questi registri permette il remapping di 1/2 periferiche secondo la tabella:

Vediamo quindi che per rimappare la funzione di ricezione della UART1 (UART1 Receive) dovremo sfruttare il registro RPINR18, andando a modificare i bit indicati come U1RXR<4:0>.

Per la UART2 si utilizza il registro RPINR19 -l’ho trovato su alcuni esempi tramite google-, ma non capisco come mai su tale documento non è menzionato, vogliano gli esperti illuminarmi su tale mancanza.

Il registro RPINR18 è  così strutturato (non dimentichiamoci che stiamo parlando di pic a 16 bit, per cui tutti i registri sono a 16bit):

come vedete tale registro permette il remapping di due funzioni di ricezione della UART: RX e CTS. Per impostare la funzione RX della UART su un pin dobbiamo quindi modificare i bit da 0 a 4 di tale registro. Essendo il C30 organizzato in strutture, ci basterà scrivere semplicemente:

RPINR18bits.U1RXR = 6;

In questo modo abbiamo associato la funzione RX della UART1 al pin denominato RP6. Basta difatti mettere nell’assegnazione il numero del pin RP che vogliamo.

Vediamo ora come associare una funzione di output. Abbiamo detto che per l’output è la periferica che viene assegnata al pin:

A sinistra abbiamo tutte le periferiche di output e quindi a sinistra il pin che sarà destinato all’uscita delle periferiche. In questo caso la selezione viene effettuata mediante i registri RPORx. Ognuno di questi registri controlla 2 pin. La funzione da associare al pin viene selezionata mediante i valori in tabella:

Ancora una volta in questa tabella manca la UART2 quindi metto un appunto qui. Per la funzione TX della UART2 il valore da utilizzare è 5 (00101).

Dovremo quindi andarci a trovare il registro RPORx relativo al pin su cui desideriamo rimappare la periferica e andare quindi a modificare i bit RPnR ed impostarli sul valore relativo alla periferica che vogliamo. Supponiamo di voler mappare la funzione TX della UART1 sul pin RP5, il registro che controlla la mappatura delle periferiche di output su RP5 è il RPOR2:

Vediamo quindi che, per il pin RP5, dobbiamo modificare i bit da 8 a 12, ed assegnare loro il valore relativo alla funzione U1TX. In C30 scriveremo quindi:

RPOR2bits.RP5R = 0b00011;

Questi esempi dovrebbero essere abbastanza chiari per capire come assegnare una qualsiasi periferica sul pin che vogliamo. All’inizio può sembrare un po’ ostico ma ci farete l’abitudine.

La periferica è bloccata!

La questione però non è conclusa: difatti per poter eseguire l’assegnazione delle periferiche è necessario eseguire un’operazione di sblocco: il remapping delle periferiche è difatti bloccato da un bit, denominato IOLOCK (Peripheral Pin Select Lock Bit), nel registro OSCCON (Oscillator Control Register). Tale funzione va eseguita necessariamente in assembler o tramite alcune macro, denominate builtin, già fornite col C30 (MPLAB® C Compiler for PIC24 MCUs and dsPIC® DSCs User’s Guide – Appendice B – Builtin functions). L’esempio di utilizzo si trova sempre nel Reference Manual.

In pratica sarà necessario eseguire in sequenza:

  • Sblocco della funzione PPS
  • Remapping delle periferiche che vogliamo
  • Blocco della funzione PPS

In C30, un esempio di codice è il seguente:

__builtin_write_OSCCONL(OSCCON & ~(1<<6)); // sblocca i registri PPS
RPINR18bits.U1RXR = 6; // assegno RX della UART1 al pin RP6
RPOR2bits.RP5R = 0b00011; // assegno TX della UART1 al pin RP5
__builtin_write_OSCCONL(OSCCON | (1<<6)); // blocco i registri

Su altri esempi, risalenti a vecchia documentazione, la funzione di blocco e sblocco viene invece eseguita in assembler, le due modalità sono equivalenti:

// sblocco registri PPS
asm volatile ( "mov #OSCCONL, w1 \n"
"mov #0x45, w2 \n"
"mov #0x57, w3 \n"
"mov.b w2, [w1] \n"
"mov.b w3, [w1] \n"
"bclr OSCCON, #6 ");
 
// blocco registri PPS
asm volatile ( "mov #OSCCONL, w1 \n"
"mov #0x45, w2 \n"
"mov #0x57, w3 \n"
"mov.b w2, [w1] \n"
"mov.b w3, [w1] \n"
"bset OSCCON, #6");
Puoi andare alla fine dell'articolo e lasciare un commento. I trackback e i ping non sono attualmente consentiti.

  1. #1 da Roberto il 9 settembre 2010

    Sei troppo avanti! ;-)
    Sei già ai PIC a 16bit, mentre io arranco ancora con gli 8 bit, con il bus I2C e con l’assembler… cmq credo che, casomai ci arrivassi anch’io, sarebbe il motivo per passare al C, in quanto possono essere programmati solo con un linguaggio ad alto livello, giusto?

    • #2 da Giovanni Bernardo il 12 settembre 2010

      Ciao. Ma che :)
      Tutti i microcontrollori possono sempre essere programmati anche in assembler, per cui anche i pic a 16 bit e i pic32. Inutile dirti che se lo farai, probabilmente sarai il primo a programmare i pic di fascia alta con l’assembler!! Non è l’assembler dei pic ad 8 bit… è una cosa troppo tosta e questa qui davvero non la usa nessuno… Ci sono un’infinità di nuove istruzioni, non c’è più un solo accumulatore ma 16, ci sono istruzioni apposite per effettuare la moltiplicazione usando il moltiplicatore hardware ecc ecc… programmare questi pic in assembler rende il codice impossibile da leggere o rilavorare in futuro. Il C30 che si usa per programmarli è totalmente ANSI e deriva dal GCC, è un linguaggio molto potente che permette di sfruttare appieno la potenza di queste bestioline.

    • #3 da Giovanni Bernardo il 12 settembre 2010

      Giusto per un assaggio, qui c’è un documento che illustra la migrazione da pic18 a pic24:

      http://ww1.microchip.com/downloads/en/DeviceDoc/39764a.pdf

      già coi pic16 il paragone è ancora piu complicato in quanto i pic16 non hanno nemmeno il moltiplicatore hardware e tante altre funzioni….

  2. #4 da Cascro il 10 settembre 2010

    Interessante… interessante davvero. Appena approfondrò a sufficienza i PIC 16 credo farò anch’io il salto di qualità, grazie ancora per tutto il materiale che ci metti a disposizione, sei un drago!

  3. #5 da Gino il 20 ottobre 2010

    Ciao, ho utilizzato anch’io questo tipo di micro sfruttando con successo la UART, tuttavia non riesco a far funzionare la SPI per l’utilizzo di una SD-CARD.
    Hai fatto prove di questo tipo? Io ho tentato di trasportare su questo micro il programma “wave player per DSPIC30F4013” ma non sono mai riuscito a far rilevare la SD-CARD!

  4. #7 da Bezul il 26 febbraio 2013

    Questo articolo è molto interessante e ben fatto, complimenti!
    Il mio interesse è catalizzato anche dall’acquisto e montaggio di un PIC24FJ64GA002 (PDIP da 28 pin), mentre precedentemente lavorai su un dsPIC33 a 100 pin (scheda Flex Full).
    Seppur con un po di esperienza fatta su tale PIC, avendo 100 pin, non c’era la periferica PPS.

    Il mio acquisto, invece, avendo solo 28 pin presenta questa funzionalità e leggendo il datasheet (sia il Family Refernce sia il capitolo sull’I/O del dispositivo in questione) più l’articolo, mi sono accinto a sperimentare la comunicazione UART.
    In particolare voglio abilitare l’UART1 e inviare (senza interrupt) ma con dei semplici controllo ai registri di trasmissione e ricezione dei dati.
    Ad esempi per trasmettere utilizzo una funzione siffatta (in buona parte mutata da codice del dsPIC):

    INT8 UART1_Send(unsigned char data)
    {
    while (U1STAbits.UTXBF); //make sure the buffer is clear
    U1TXREG = data;
    while(!U1STAbits.TRMT);
    return 0;
    }

    Il problema è che pare che pin associati agli RPn non vengono impostati correttamente dalla PPS, non configurando correttamente la periferica!

    Come primo esperimento per abilitarla, ho utilizzato il codice che si trova sul documento:

    http://ww1.microchip.com/downloads/en/DeviceDoc/39711b.pdf

    a pag.17 e successivamente la proposta fatta nell’articolo.

    Avendo lo stesso fallimentare risultato, inoltre ho notato che le macro :

    __builtin_write_OSCCONL(OSCCON & 0xbf)
    __builtin_write_OSCCONL(OSCCON | 0x40)

    non vengono riconosciuti, e infatti non sono presenti nella libreria del pic24FJ64GA002 ! (però l’assembly dovrebbe essere equivalente e riconosciuto).

    Probabilmente sto facendo un errore (stupido e grossolano) data dalla mia inesperienza, e mi piacerebbe studiare un esempio, o in generale avere una mano da voi più esperti; anche perché ho visto che il progetto OrBit Sedici è basato sul mio stesso modello di PIC, quindi sarebbe fantastico poter avere delle indicazioni ad esempio:
    -su quali librerie richiamare nel progetto
    -come e dove (nel codice, io l’ho messo come prime istruzioni del main() ) attivare lo sblocco dei registri, l’impostazioni delle periferiche e il successivo blocco
    -impostare il PPS in maniera che i pin si configurino correttamente.

    Vi ringrazio in anticipo, e concludo dicendo di star utilizzando MPLAB v8.43 con queste librerie

    #include
    #include “p24FJ64GA002.h”
    #include
    #include

    richiamate nel file “.c” principale(ed unico) del progetto avendo incluso, nella struttura di progetto: Header File la libreria p24FJ64GA002.h e come Linker Script “PIC24FJ64GA002.gld”

    Un altro appunto, prima di utilizzare la “sequenza di sblocco” del registro e impostare la PPS devo inserire altre istruzioni? (Ad esempio impostare tutti i pin in digitale ecc..?)

    Grazie mille e scusate per la lunghezza del post! :)

  5. #8 da Bezul il 26 febbraio 2013

    #include “p24fxxxx.h”
    #include “p24FJ64GA002.h”
    #include “GenericTypeDefs.h”
    #include “libpic30.h”

  6. #9 da RobertOne il 4 febbraio 2016

    Ciao Giovanni, scusa la mia ignoranza, sapresti dirmi se è necessario impostare il registro LATC per i pin che vanno rimappati ??
    Oppure la periferica prende automaticamente il predominio del pin ??

    Grazie per il chiarimento.

    Saluti

    Roberto

Devi essere collegato per lasciare un commento.

  1. Ancora nessun trackback
Settorezero.com e il logo Zroid™ ©2007÷2017 Giovanni Bernardo - E' vietata la copia e la distribuzione anche parziale dei contenuti di questo sito web senza l'esplicito consenso dell'autore. I contenuti di settorezero.com sono distribuiti sotto una licenza Creative Commons Attribuzione-Non Commerciale-Non Opere derivate 2.5 Italia e sono soggetti alle condizioni definite nel disclaimer. Settorezero.com e tutti i suoi contenuti sono tutelati dalla legge sul diritto d'autore per cui i trasgressori sono perseguibili a norma di legge. Settorezero fa uso dei cookie leggi l'informativa estesa. Il tema di questo sito è basato sul tema Fusion per wordpress, realizzato originariamente da digitalnature e fa uso del plugin Wassup per il computo delle statistiche. Per contattare l'autore siete pregati di utilizzare la sezione contatti. Siamo presenti anche su Facebook e, meno assiduamente, anche su Twitter - Tumblr - Google+ - Blogspot - Youtube.
Creative Commons BY-NC-ND 2.5