Introduction

Le composant 23LCV1024 de Microchip (documentation) est une mémoire à accès aléatoire, c’est à dire volatile – perte de l’information lorsqu’elle n’est plus alimentée – de type statique, c’est à dire sans nécessité de rafraîchir les données régulièrement. Elle peut être pilotée via une interface SPI (voir tutoriel) jusqu’à 20~MHz.

Elle peut stocker 1 Mibits soient 128 kio, soit 2 x 256 x 256 adresses différentes. Son temps de réponse est d’environ 30 ns. Elle a un jeu d’instructions très limité (voir tableau ci-dessous). Il existe trois modes de transfert décrits dans la documentation : le mode séquentiel (SEQ), le mode page (PAGE) et le mode octet par octet (BYTE).

Instructions de la SRAM 23LCV1024 – Documentation de la 23LCV1024 / Table 2-1

Transfert de données

Pour pouvoir lire ou écrire une donnée dans cette mémoire à accès aléatoire, il est nécessaire de transmettre :

  • une commande, sur un octet, soit WRITE soit READ
  • une adresse, sur 3 octets (17 bits utilisés)
  • une donnée (ou plusieurs données) – transmise ou reçue, selon le mode lecture ou écriture choisi

Les figures suivantes montrent la lecture et l’écriture d’une donnée à une adresse particulière.

Transfert de données en SPI – Documentation de la 23LCV1024 / Figures 2-1 et 2-2

Utilisation de la SRAM avec un PIC16F15xx

Bibliothèque de fonctions

Une bibliothèque de fonctions permettant d’utiliser la SRAM en mode SPI est disponible ici : sram.h / sram.c. Elle nécessite l’utilisation de la bibliothèque spi.h / spi.c (voir le tutoriel).

Cette bibliothèque contient les fonctions suivantes :

  • void initRAM(void) : initialiser la mémoire SRAM en mode octet par octet (BYTE_MODE)
  • void changeModeRAM(char mode) : changer le mode de fonctionnement du transfert de données
  • void writeRAM(char val, char adH, char adC, char adL) : stocker la donnée val à l’adresse passée en argument (3 octets)
  • char readRAM(char adH, char adC, char adL) : récupérer une donnée à l’adresse passée en argument (3 octets)

Ces fonctions sont détaillées dans la suite de ce tutoriel.

Connexion SPI entre le PIC16F1509 et la SRAM 23LCV

Les broches de connexion de la liaison SPI entre le microcontroleur PIC16F1509 et la SRAM 23LCV1024 peuvent être les suivantes :

  • SCK : broche RB6 / configurée en sortie
  • SDO : broche RC7 / configurée en sortie
  • SDI : broche RB4 / configurée en entrée
  • SS : broche RC2 / configurée en sortie

Initialisation de la communication

Pour initialiser la communication entre la SRAM et le PIC, il est nécessaire de faire appel à la fonction initSPI(0) de la bibliothèque spi.h puis à la fonction initRAM() de la bibliothèque sram.h.

void initRAM(void) {
    // CS RAM
    TRISCbits.TRISC2 = 0;
    CS_RAM = 1;
    __delay_ms(10);

Ces premières lignes permettent d’initialiser la broche SS en sortie et de lui affecter la valeur ‘1’.

    CS_RAM = 0;
    __delay_ms(1);
    sendSPI(RSTIO);
    __delay_ms(1);
    CS_RAM = 1;
    __delay_ms(10);

Ensuite, on amorce la discussion en faisant baisser le signal SS associé à la SRAM. On envoie la commande de réinitialisation RSTIO (voir table 2-1 de la documentation). On refait ensuite passer SS à ‘1’ et on laisse un délai de 10 ms pour laisser le temps à la SRAM de s’initialiser.

    CS_RAM = 0;
    __delay_ms(1);
    sendSPI(WRMR_RAM);
    sendSPI(BYTE_MODE);
    __delay_ms(1);
    CS_RAM = 1;
    __delay_ms(10);
}

Cette dernière partie permet d’écrire dans le registre de configuration du mode (commande WRMR_RAM) la commande permettant de passer dans un mode de transfert octet par octet (ici BYTE_MODE).

L’ensemble des commandes sont transmises à l’aide de la fonction void sendSPI(char data) de la bibliothèque spi.h.

Ecriture d’une donnée

L’envoi d’une donnée se fait selon le protocole établi dans la documentation technique de la SRAM : envoi de la commande d’écriture (WRITE_RAM), envoi des 24 bits de l’adresse (soit 3 octets) en commençant par les poids forts, envoi de la donnée à écrire.

void writeRAM(char val, char adH, char adC, char adL){
    CS_RAM = 0;
    sendSPI(WRITE_RAM);
    sendSPI(adH);
    sendSPI(adC);
    sendSPI(adL);
    sendSPI(val);
    CS_RAM = 1;
    return;
}

Par exemple, pour stocker la valeur 0x33 à l’adresse 26.876 de la SRAM, il faut écrire :

int adresse = 26876;
writeRAM(0x33, adresse >> 16, adresse >> 8, adresse);

Lors de l’affectation des 3 octets des adresses, seul l’octet de poids faible est conservé.

Lecture d’une donnée

La lecture d’une donnée se fait selon le protocole établi dans la documentation technique de la SRAM : envoi de la commande de lecture (READ_RAM), envoi des 24 bits de l’adresse (soit 3 octets) en commençant par les poids forts, envoi d’une donnée “inutile” pour récupérer l’information transmise par l’esclave.

char readRAM(char adH, char adC, char adL){
    char read_data = 0;
    CS_RAM = 0;
    sendSPI(READ_RAM);
    sendSPI(adH);
    sendSPI(adC);
    sendSPI(adL);
    sendSPI(0x00);
    while(PIR1bits.SSP1IF == 0);
    read_data = SSPBUF;
    CS_RAM = 1;
    return read_data;
}

Par exemple, pour récupérer la valeur stockée à l’adresse 26.876 de la SRAM, il faut écrire :

int adresse = 26876;
char data = 0;
data = readRAM(adresse >> 16, adresse >> 8, adresse);

Exemples d’utilisation

Initialisation de la RAM à zéro

Pour initialiser toutes les cases de la SRAM à la valeur 0, il faut tout d’abord faire appel aux fonctions d’initialisation du microcontroleur, puis de la liaison SPI et enfin de la SRAM.

void main(void) {
    char i, j;
    initPIC();
    initSPI();
    initRAM();

Ensuite, on parcourt l’ensemble des cases mémoires à l’aide de deux boucles imbriquées for, permettant de parcourir 256 * 256 cases. On appelle la fonction writeRAM() pour pouvoir stocker la valeur 0 (premier argument) à l’adresse pointée par les variables incrémentées par les boucles for.

    for(j = 0; j < 255; j++){
        for(i = 0; i < 255; i++){
            writeRAM(0, 0, j, i);
        }
    }
    for(j = 0; j < 255; j++){
        for(i = 0; i < 255; i++){
            writeRAM(0, 1, j, i);
        }
    }
}

Pour remplir l’ensemble des cases, il est nécessaire de parcourir 2 fois 256 * 256 cases mémoires (ce qui même à 128 kio au final).

Générateur de signal

Un premier exemple pour tester le bon fonctionnement de ces fonctions est la réalisation d’un générateur de signal, à l’aide d’un convertisseur numérique analogique en sortie par exemple.

On va dans un premier temps initialiser le microcontroleur et la SRAM (ainsi que les autres périphériques au besoin) :

void main(void) {
    char i, j, res;
    initPIC();
    initSPI();
    initDAC();  // pour initialiser le convertisseur numérique analogique
    initRAM();

On va ensuite initialiser la RAM avec un motif particulier, par exemple ici, un signal triangulaire (simple à réaliser, mais on pourrait faire d’autres motifs).

    for(j = 0; j < 255; j++){
        for(i = 0; i < 255; i++){
            if(j%2 == 0)   writeRAM(i, 0, j, i);
            else    writeRAM(255-i, 0, j, i);
        }
    }

Ce signal pré-enregistré va alors servir de référence pour le convertisseur numérique analogique (ici par exemple un AD7303 – voir tutoriel).
On lit successivement les données contenues dans la RAM pour les envoyer sur le CNA.

    while(1){
        for(j = 0; j < 255; j++){
            for(i = 0; i < 255; i++){
                res = readRAM(0, j, i;
                changeDACA_IntRef(data);
                __delay_ms(1);
            }
        }
    }
Microchip PIC16F / Utiliser une mémoire RAM / MCP 23 LCV1024 / PIC16F15xx