Un processore in banda base di semplice utilizzo per transceiver RF

Al giorno d’oggi, i sistemi wireless sono ovunque e il numero dei dispositivi e dei servizi wireless è in continua crescita. Il progetto di un sistema RF completo è una sfida multidisciplinare, la cui parte più critica è rappresentata dal front-end RF analogico. Tuttavia, la disponibilità di transceiver RF integrati come l’AD9361 riduce grandemente le sfide poste dall’RF sui progetti di questo tipo. Questi transceiver forniscono un’interfaccia digitale per la catena di segnale analogico RF e consentono la facile integrazione di un ASIC o FPGA per l’elaborazione in banda base. Il processore in banda base (Base Band Processor, BBP) permette di elaborare i dati nel dominio digitale tra l’applicazione finale e il transceiver. Gli strumenti di modellazione quali Simulink rendono più facile la progettazione del processore Base Band. Tuttavia, un utilizzatore non esperto potrebbe trovare difficile comprendere e collocare questo pezzo del “puzzle” del sistema di comunicazione. Questo articolo descrive un esempio di progettazione e implementazione di un processore RF in banda base per un sistema di comunicazione wireless. Il progetto è implementato sulle piattaforme AD-FMCOMMS2-EBZ e Xilinx ZC706 usando il reference design dell’AD9361.

La prima parte dell’articolo descrive in dettaglio i principi generali per la progettazione del base band processor. Questa sezione è per lo più un’introduzione teorica del BBP. Nella seconda parte, viene trattata la reale implementazione hardware usando l’FPGA reference design AD9361 di Analog Devices. Si noti che lo scopo principale è quello di mantenere il progetto il più possibile semplice e dimostrare un trasferimento dati veloce via etere in un ambiente di laboratorio.

Progetto base

In Figura 1 è illustrato un tipico sistema RF, con l’eccezione dei sistemi RF diretti. Nella Figura 1 viene mostrato un singolo data-path, quello inverso ne è l’immagine speculare. Il processore in banda base presentato in questo articolo consente di elaborare i dati in modo tale che siano trasferiti via etere tra due sistemi RF. I requisiti del progetto base sono discussi in seguito.

Figura 1. Schema a blocchi del Sistema RF.

 

I dati vengono ripetuti su entrambi i segnali ortogonali I&Q

Si noti che le portanti sono indipendenti e asincrone l’una rispetto all’altra. Di conseguenza ci sono degli offset in fase e frequenza tra le portanti di trasmissione e ricezione. Questo ha un effetto negativo sulla demodulazione dal lato del ricevitore. Un problema significativo è l’inversione del segnale, i segnali ortogonali possono invertire i propri ruoli dato che gli offset coincidono e si allontanano periodicamente. Un metodo semplice per superare questa ambiguità consiste nel ripetere gli stessi dati su entrambi i segnali ortogonali.

I dati sono trasmessi e ricevuti serialmente (Bit-per-Bit)

L’interfaccia di front-end RF verso il BBP è costituita nella maggior parte dei casi da un DAC e un ADC. Queste sono le interfacce digitali di un segnale analogico. In questo modo, non è possibile inviare semplicemente i dati all’ingresso del DAC e aspettare lo stesso all’uscita dell’ADC. I dati vengono trasmessi serialmente, mappando il singolo bit dati alla piena risoluzione del DAC. Allo stesso modo, i dati sono ricevuti serialmente, demappati dalla piena risoluzione dell’ADC. Ciò fornisce un ampio spazio di ridondanza. Se questi fossero stati convertitori a 16-bit, il ricevitore avrebbe dovuto discriminare tra 1 e 0 da un possibile set di 65536 dati. Questo semplifica significativamente la decodifica.

I segnali I&Q sono ortogonali l’uno rispetto all’altro

Il dispositivo di front-end RF (come l’AD9361) è un ricetrasmettitore I/Q. Questi dispositivi lavorano al meglio delle possibilità se agli ingressi vengono inviati segnali ortogonali. Solitamente dispongono di una funzione interna di confronto e correzione I/Q lungo i due percorsi dati in modo da compensare qualsiasi variazione tra di loro. Convenzionalmente il segnale reale (I) è la funzione coseno e il segnale immaginario (Q) la funzione seno.

Lo schema di modulazione è BPSK

È possibile utilizzare tutti i metodi comunemente conosciuti, ampiezza, frequenza, o modulazione di fase dei segnali. È relativamente più semplice rilevare differenze di fase. Dal momento che i dati sono trasferiti serialmente, la scelta più logica ricade sul “binary phase shift keying” (BPSK).

L’intervallo di bit equivale a otto campionature

I dati richiedono informazioni di timing, l’intervallo di bit. Il massimo intervallo di bit possibile equivale al periodo di campionamento. Per mantenere semplice il progetto del ricevitore, è necessario lasciare un tempo sufficientemente lungo per decodificare il segnale e prendere una decisione. I metodi più semplici di timing recovery sono il passaggio per lo zero (zero crossing) e la rilevazione del picco. In questo caso i picchi non sono consistenti. Per questo, per la rilevazione e la tracciatura degli intervalli di bit viene scelto lo zero crossing. Ci sono anche differenze di portante tra i due sistemi. In alcuni casi, un campionamento potrebbe essere ambiguo su un versante qualsiasi dei dati utente. Consentendo quattro campionamenti per ciascuna metà del segnale sinusoidale, l’intervallo di bit è stabilito in otto campionamenti. In questo modo, la velocità di trasferimento effettiva corrisponde alla frequenza di campionamento divisa per otto.

I dati non hanno un contenuto DC

Il timing, con il relativo recupero di fase, è basato sullo zero crossing dei segnali. Perciò, i singoli segnali devono essere esenti da qualsiasi contenuto DC. È anche necessario che il segnale permetta almeno un passaggio per lo zero per ogni intervallo di bit. Un segnale sinusoidale possiede entrambe queste caratteristiche e si adatta molto bene con lo schema di modulazione BPSK menzionato in precedenza.

I dati sono codificati

I dati utente sono arbitrari — potrebbero consistere in una lunga sequenza di 1 o 0. Per consentire il recupero di timing e fase dal lato del ricevitore, i dati vengono codificati per tracciare il segnale in modo più efficace.

I dati sono trasferiti in pacchetti

È previsto che i dati in arrivo al ricevitore abbiano ampiezza, frequenza ed errore di fase tali per cui i sistemi siano vicendevolmente asincroni. Il segnale demodulato è una variazione di fase del segnale trasmesso rispetto alla portante locale. Le portanti possono occasionalmente agganciarsi, perdere dati, e agganciarsi nuovamente. Per questo motivo il progetto deve poter gestire una perdita di dati. Per correggere questo aspetto, i dati vengono trasferiti in pacchetti. Alcuni di questi pacchetti possono essere ripetuti a favore dell’integrità dei dati.

I pacchetti sono convalidati utilizzando il CRC

I pacchetti contengono un carattere di “cyclic redundancy check” (CRC) in modo tale che in presenza di una differenza il ricevitore possa scartarli e chiederne il rinvio.

Il timing con correzione di fase viene eseguito durante ogni preambolo

L’header del pacchetto contiene un preambolo per distinguerlo dal flusso dati ricevuto. Questo preambolo è anche usato dal ricevitore per il reset delle informazioni di timing e fase dei segnali per demodulare i dati del pacchetto.

Misurazione interna delle prestazioni

Il ricevitore supporta anche contatori statistici per il numero di pacchetti ricevuti, persi, o corretti. Questi contatori sono usati per misurare e monitorare le prestazioni di sistema, incluse la frequenza di bit error e la velocità effettiva di comunicazione.

Riassumendo, i dati vengono trasmessi e ricevuti serialmente sotto forma di pacchetti. I pacchetti sono dotati di preambolo e CRC. I dati sono modulati e demodulati in BPSK su segnali ortogonali intermedi prima che arrivino al transceiver. La frequenza del segnale intermedio e, di conseguenza, la velocità dei dati è un ottavo di quella di campionamento. Il modulo del processore in banda base con i dettagli del progetto descritto in precedenza è illustrato nelle Figure 2 e 3.

Figura 2. Schema a blocchi funzionale del trasmettitore BBP.

 

Figura 3. Schema a blocchi funzionale del ricevitore BBP.

Il trasmettitore legge byte di dati (larghezza di carattere) e li converte in pacchetti con un header o preambolo. In coda a ciascun pacchetto viene aggiunto un CRC. Successivamente i dati del pacchetto vengono codificati e serializzati. Il singolo bit dati modula quindi in fase una funzione coseno (I) e seno (Q) prima di interfacciarsi al transceiver.

Nel senso della ricezione, un modulo offline recupera e traccia gli intervalli di timing e la relativa fase del segnale modulato. Questa informazione viene utilizzata per recuperare i dati seriali dai campioni in arrivo dall’ADC. In seguito vengono assemblati a pacchetti e decodificati. Alla fine del pacchetto, il CRC viene confrontato e, se non c’è corrispondenza, scartato. Se il CRC corrisponde, i dati vengono trasferiti all’utente.

Implementazione

Il progetto del BBP è implementato e collaudato via hardware. L’hardware è costituito dalla combinazione di due schede di valutazione: la Xilinx ZC706 dotata di FPGA Zynq e la AD-FMCOMMS3-EBZ con a bordo il transceiver AD9361. A supporto di questo hardware, ADI fornisce un progetto di riferimento completo. Questo progetto open-source è disponibile gratuitamente, completamente supportato e aggiornato.

I dettagli relativi all’hardware si possono trovare ai seguenti URL:

ZC706

AD-FMCOMMS3-EBZ

Zynq SOC

AD9361

ADI GitHub Repository

ZC706 and AD-FMCOMMS3-EBZ HDL Reference Design

AXI AD9361 IP

Il progetto di riferimento ADI consiste in un sistema embedded che supporta il framework Linux. È formato da diverse periferiche attorno ai processori ARM. Il dispositivo AD9361 si interfaccia alla periferica IP axi_AD9361. Trasferisce i dati campionati grezzi dal dispositivo RF alla memoria di sistema.

Le periferiche e i dispositivi sono inizializzati e controllati attraverso i driver del kernel Linux. Il BBP è implementato come un’altra periferica IP che si interfaccia all’ axi_AD9361. IL BBP IP è definito axi_xcomm2ip per motivi storici. Per controllare, inviare e ricevere dati tra i sistemi si usa un’applicazione nello spazio utente di Linux.

Nel progetto di riferimento ADI, l’IP axi_AD9361 si interfaccia a un modulo di “unpack ” (util_upack) nel senso della trasmissione e a uno di “pack” (util_cpack) in quello della ricezione. Nel verso di trasmissione, i dati BBP sono inseriti tra il modulo di unpack e il core dell’AD9361. Per far sì che questo non coinvolga il percorso dati di default, il BBP supporta un multiplexer opzionale sul percorso dati per selezionare la sorgente dei dati “unpacked” oppure la sorgente BBP. Il BBP riconosce il percorso dati del progetto di riferimento come scelta di default e seleziona la sorgente BBP solo quando è abilitata. Nel verso della ricezione, il BBP si interfaccia semplicemente al core dell’AD9361, il data path non ne rimane coinvolto. Questo permette al framework di eseguire il boot e il set up del sistema senza impedimenti. Al termine del setup di sistema, il BBP è abilitato a iniziare il trasferimento dati ignorando il percorso dati di default. Nella Figura 4 è illustrato lo schema a blocchi del BBP nel modo in cui è stato implementato nel reference design ADI.

Figura 4. Schema a blocchi del BBP.

Il progetto, l’inizializzazione e il trasferimento dati discussi in questo articolo utilizzano una coppia di queste schede. Il setup richiede solamente un paio di monitor HDMI®, tastiera, mouse e antenne.

I sistemi sono completamente asincroni l’uno rispetto all’altro ma richiedono la stessa impostazione. I dati vengono trasferiti su portanti diverse in ciascuna direzione. La frequenza della portante di trasmissione del dispositivo 1 e quella di ricezione del dispositivo 2 sono identiche, ma differenti nell’altro senso. Tuttavia, usando un unico dispositivo in loopback, le portanti di trasmissione e ricezione devono avere la stessa frequenza. Il progetto HDL del BBP utilizza i moduli della libreria ADI.

Interfaccia di controllo (microprocessore)

Per il controllo e il monitoraggio del BBP il processore utilizza un’interfaccia AXI-Lite. Questo modulo d’interfaccia viene ricavato in modo semplice dal modulo up_axi, tratto dalla libreria comune ADI (hdl/library/common/up_axi.v).

Questo modulo riduce l’interfaccia AXI-Lite a una specie di semplice bus di memoria di lettura-scrittura. I registri interni e la memoria vengono aggiunti proprio come qualsiasi altro IP ADI.

La mappa di registro è dettagliata nella Tabella 1.

Tabella 1. Mappa di registro del BBP

Indirizzo Registro Tipo
  Campi Nome Descrizione Default
0x000 XCOMM2IP_VERSION     RO
  31:0 VERSION Versione IP. 0x40063
0x008 XCOMM2IP_SCRATCH     RW
  31:0 SCRATCH Registro scratch 0x0
0x800 XCOMM2IP_TX_RESET     RW
  0 TX_RESET Se impostato a 0x1, la trasmissione va in reset. Per il funzionamento normale questo bit deve essere impostato a 0x0. 0x1
0x804 XCOMM2IP_TX_ENABLE     RW
  0 TX_ENABLE Se impostato a 0x0, il percorso dati resta invariato e i dati UNPACK vengono trasmessi al DAC. Se impostato a 0x1, al DAC vengono trasmessi i dati dal BBP. 0x0
0x808 XCOMM2IP_TX_REQ     RW
  0 TX_REQ Se impostato dal software, inizia un trasferimento di pacchetti nel verso della trasmissione. Questo bit viene resettato automaticamente dall’hardware quando il trasferimento e completo. 0x0
0x80C-0x87C XCOMM2IP_TX_PKT_DATA_3-XCOMM2IP_TX_PKT_DATA_31     W
  7:0 TX_PKT_DATA_3-TX_PKT_DATA_31 I byte da 3 a 31del pacchetto dati. L’hardware usa i primi tre byte come header e l’ultimo byte come CRC. W
0xC00 XCOMM2IP_RX_RESET     RW
  0 RX_RESET Se impostato a 0x1, la ricezione va in reset. Per il funzionamento normale questo bit deve essere impostato a 0x0 0x1
0xC08 XCOMM2IP_RX_REQ     RW
  0 RX_REQ Se impostato dall’hardware, indica che un pacchetto è stato ricevuto e deve essere letto dal software. Il software deve resettare questo bit dopo aver letto i dati del pacchetto. Tutti i pacchetti che seguono vengono eliminati fino a che questo bit non è stato resettato dal software. 0x0
0xC0C-0xC7C XCOMM2IP_RX_PKT_DATA_3-XCOMM2IP_RX_PKT_DATA_31     W
  7:0 RX_PKT_DATA_3-RX_PKT_DATA_31 I byte dati da 3 a 31 del pacchetto. L’hardware usa i primi tre byte come header e l’ultimo byte come CRC. W

 

Le porte del modulo up_axi e le rispettive mappature sono descritte in seguito.

up_rstn: reset d’interfaccia AXI (asincrono attivo basso), connesso a s_axi_aresetn.

up_clk: clock d’interfaccia AXI, connesso a s_axi_aclk.

up_axi_*: segnali d’interfaccia AXI, connesso alle equivalenti porte s_axi_*.

up_wreq, up_waddr, up_wdata, up_wack: L’interfaccia interna di scrittura, il segnale up_wreq, viene asserito unitamente a indirizzo e dati per indicare una richiesta di scrittura. La richiesta deve ricevere l’acknowledge attraverso la porta up_wack.

Un semplice registro di scrittura si implementa come segue.

  always @(negedge up_rstn or posedge up_clk) 
  begin
  if (up_rstn == 0) begin
  up_wack <= ‘d0;
  up_reg0 <= UP_REG0_RESET_VALUE;
  end else begin
  up_wack <= up_wreq_s;
  if ((up_wreq_s == 1’b1) && (up_waddr == UP_ REG0_ADDRESS)) begin
  up_reg0 <= up_wdata[UP_REG0_WIDTH-1:0];
  end
  end
  end

Il modulo esegue una traslazione di indirizzo tra i due. L’interfaccia AXI utilizza indirizzi in byte, ma il bus interno usa indirizzi DWORD. Il risultato è che il modulo up_axi scarta i due bit meno significativi dell’indirizzo AXI per generare l’indirizzo interno DWORD.

up_rreq, up_raddr, up_rdata, up_rack: L’interfaccia interna di lettura, il segnale up_rreq, viene asserito unitamente all’indirizzo per indicare una richiesta di lettura. La richiesta deve ricevere l’acknowledge attraverso la porta up_rack unitamente ai dati letti.

Qui sotto lo stesso registro implementato per la lettura.

  always @(negedge up_rstn or posedge up_clk)
  begin
  if (up_rstn == 0) begin
  up_rack <= ‘d0;
  up_rdata <= ‘d0;
  end else begin
  up_rack <= up_rreq_s;
  if ((up_rreq_s == 1’b1) && (up_raddr == UP_ REG0_ADDRESS)) begin
  up_rdata <= up_reg0;
  end else begin
  up_rdata <= 32‘d0;
  end
  end
  end

La stessa traslazione di indirizzo si applica anche alla lettura. La lettura dei dati avviene soltanto a richiesta, altrimenti viene impostata a zero. Questo perché il modulo up_axi passa le singole letture di dati da vari blocchi di indirizzo a una porta OR. In questo modo, i blocchi che non vengono selezionati vengono letti a zero.

Il BBP ha tre campi di indirizzo come elencato nella mappa di registro precedente. Lo spazio comune di registro è mappato a 0x000, la trasmissione (DAC) è mappata a 0x800 (0x200), e la ricezione (ADC) è mappata a 0xC00 (0x300). È previsto che il software (applicazione Linux nello spazio utente) scriva su un buffer di pacchetti dati da trasmettere e legga i pacchetti dati ricevuti da un altro buffer. La dimensione scelta per il pacchetto è di 32 byte con un preambolo di 3 byte e 1 byte di CRC.

Interfaccia dati

Il core dell’interfaccia AD9361 consiste in due coppie di dati I/Q a 16-bit per i due canali in trasmissione e ricezione. Il core funziona alla medesima frequenza di clock dell’interfaccia digitale AD9361. In modalità 2R2T, questo equivale alla frequenza di campionamento ×4. In modalità 1R1T, il clock equivale alla frequenza di campionamento ×2. La velocità effettiva di trasmissione dei dati è controllata dal segnale di validità. Così, nella modalità 2R2T il segnale valid viene asserito una volta ogni quattro clock. In modalità 1R1T viene asserito ogni due clock. Il BBP è concepito per supportare sia la modalità 2R2T che la 1R1T. Utilizza un singolo canale per trasmissione e ricezione. La logica interna è strutturata per funzionare alla frequenza di campionamento sia nella modalità 2R2T che nella 1R1T. In seguito il BBP trasferisce i dati con il core d’interfaccia che funziona alla propria frequenza di clock. Questo è fatto intenzionalmente, per dimostrare la conversione di clock all’interno del BBP. In molti casi per l’utente sarebbe possibile far girare la logica del BBP alla frequenza di campionamento, indipendentemente dalla velocità d’interfaccia del transceiver.

Il clock interno, alla frequenza di campionamento, è generato utilizzando le primitive Xilinx BUFR e BUFG. BUFR è un divisore e BUFG è un buffer di clock ad alto fan-out. A questo scopo è anche possibile utilizzare un MMCM. Il clock interno è generato come segue.

parameter XCOMM2IP_1T1R_OR_2T2R_N = 0; localparam XCOMM2IP_SCLK_DIVIDE = (XCOMM2IP_1T1R_OR_2T2R_N == 1) ? “2” : “4”;

BUFR #(.BUFR_DIVIDE(XCOMM2IP_SCLK_DIVIDE)) i_bufr (
    .CLR (1’b0),
    .CE (1’b1),
    .I (clk),
    .O (s_clk_s));

BUFG i_bufg (
    .I (s_clk_s),
    .O (s_clk));

L’uso di BUFR e BUFG garantisce che la frequenza dei clock sia bloccata, a costo della certezza della fase. La massima ambiguità di fase equivale a un singolo periodo del clock d’interfaccia. Questo si compensa facilmente attraverso un array di registro a quattro stadi con un segnale di sincronizzazione. Tuttavia, per implementare il trasferimento dei dati il progetto utilizza moduli RAM a doppia porta.

Gli elementi RAM a doppia porta sono ricavati dai moduli di memoria (ad_mem) della libreria ADI.

Interfaccia di trasmissione

Nel verso della trasmissione, il processore scrive un pacchetto di dati in un buffer (vedi la precedente mappa di registro). Quindi richiede all’hardware di inviarlo. Il BBP invia pacchetti al dispositivo in modo continuo. All’inizio di un pacchetto, verifica l’esistenza di richieste. Se non ci sono richieste pendenti, trasmette un pacchetto vuoto. Se c’è una richiesta, il buffer viene letto e il pacchetto viene trasmesso.

La logica di trasmissione funziona per ampiezza di bit, usando un bit counter di tipo free running. Quando il bit counter si trova a 0x0, l’indirizzo del buffer di lettura viene aggiornato. Dato che durante il trasferimento di un pacchetto può arrivare in qualsiasi momento una richiesta dal processore, questa viene catturata immediatamente e cancellata all’inizio del trasferimento del pacchetto. Se esiste una richiesta pendente all’inizio del trasferimento, viene inviato un acknowledge di ritorno all’interfaccia del processore. La richiesta viene utilizzata per la selezione tra dati di buffer e dati vuoti.

Figura 5. Percorso dati di trasmissione.

I primi due byte del pacchetto dati sono impostati a 0xfff0. Il terzo byte è usato per indicare un pacchetto vuoto (0xc5) o un pacchetto dati (0xa6). Il byte di CRC viene inserito come ultimo byte del pacchetto. Il polinomio di CRC è x8 + x2 + x + 1. Tutti i byte ad eccezione dell’header sono codificati. Il polinomio di codifica è lo stesso di SONET/SDH (x7 + x6 + 1).

Per generare la portante modulata si usa una lookup table di seno e coseno. L’intervallo di bit raggiunge un ciclo completo di segnale (da 0 a 2π) in otto campionature. Il data bit viene usato per invertire il segnale. Successivamente i dati vengono scritti in un piccolo buffer e letti basandosi sul segnale di validità proveniente dal core dell’AD9361 usando il clock d’interfaccia.

Interfaccia di ricezione

Nel verso di ricezione, i dati I/Q vengono monitorati per la presenza del pattern 0xfff0 nell’header. Questo è l’unico pattern che appare una sola volta nel trasferimento di un pacchetto. È possibile che vengano inviati pacchetti di dati nei quali il codificatore d’uscita ripete questo pattern. Questa eventualità viene scoraggiata e prevenuta dal software. Questa serie di sequenze dati in-fase per 12 intervalli di bit consecutivi viene usata per il reset e la tracciatura di timing e fase del ricevitore da parte del modulo di timing recovery. In questo modo, resetta i propri contatori di timing e imposta il valore di fase a 0x1. La prima inversione dopo questa sequenza viene considerata 0x0. In seguito, il modulo di timing recovery mantiene il proprio stato durante il trasferimento del pacchetto.

Il modulo di data recovery valuta il segnale e ne stabilisce il valore di fase corrente. Quest’ultimo viene poi confrontato col valore di fase relativo tracciato dal modulo timing recovery. In caso di conflitto, la discriminazione è basata sulle ultime variazioni di segnale. Questo avviene perché di solito i conflitti nascono dal cambio di fase.

Figura 6. Percorso dati di ricezione.

Il flusso di bit demodulato viene quindi organizzato in byte e decodificato. I dati vengono scritti nel buffer di trasferimento, se è vuoto. Il CRC viene verificato alla fine del pacchetto. Se corrisponde e il buffer di trasferimento viene scritto, l’interfaccia del processore riceve una notifica. È previsto che il software monitorizzi questa richiesta e, se ricevuta, svuoti il buffer leggendone il contenuto. In seguito deve resettare la richiesta per permettere il trasferimento di ulteriori pacchetti.

Istruzioni per la realizzazione e download

Questo articolo fornisce le basi teoriche e le specifiche di implementazione per un semplice processore RF in banda base. Viene discussa l’implementazione pratica di questo progetto su hardware ZC706 e AD-FMCOMMS3-EBZ. I file completi di progetto e le istruzioni di realizzazione per una dimostrazione veloce sono disponibili sul sito https://wiki.analog.com/resources/fpga/docs/hdl/xcomm2ip. La pagina wiki riporta anche i dettagli su progetto HDL, software, setup RF, prestazioni e analisi.

A cura di Rejeesh Kutty, Digital Design Engineer, Analog Devices.

 

 

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Main Menu