Le périphérique SPI de mon AT91SAM7X512 est désactivé à l'heure X (X varie) où j'écris dans la base de données. SPI_TDR
. En conséquence, le processeur s'accroche à la boucle while qui vérifie les données de la TDRE
le drapeau en SPI_SR
. Cette boucle while est située dans la fonction SPI_Write()
qui appartient au progiciel/à la bibliothèque fournis par ATMEL. Le problème survient de manière arbitraire - parfois tout fonctionne bien et parfois il échoue lors de tentatives répétées (tentative = télécharger le même binaire sur le MCU et exécuter le programme).
Les configurations sont (définies dans l'ordre d'écriture) :
-
SPI_MR
:-
MSTR
= 1 -
PS
= 0 -
PCSDEC
= 0 -
PCS
= 0111 -
DLYBCS
= 0
-
-
SPI_CSR[3]
:-
CPOL
= 0 -
NCPHA
= 1 -
CSAAT
= 0 -
BITS
= 0000 -
SCBR
= 20 -
DLYBS
= 0 -
DLYBCT
= 0
-
-
SPI_CR
:-
SPIEN
= 1
-
Après avoir défini les configurations, le code vérifie que le SPI est activé, en vérifiant le paramètre SPIENS
drapeau.
J'effectue une transmission d'octets comme suit :
const short int dataSize = 5;
// Filling array with random data
unsigned char data[dataSize] = {0xA5, 0x34, 0x12, 0x00, 0xFF};
short int i = 0;
volatile unsigned short dummyRead;
SetCS3(); // NPCS3 == PIOA15
while(i-- < dataSize) {
mySPI_Write(data[i]);
while((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
dummyRead = SPI_Read(); // SPI_Read() from Atmel's library
}
ClearCS3();
/**********************************/
void mySPI_Write(unsigned char data) {
while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0);
AT91C_BASE_SPI0->SPI_TDR = data;
while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE) == 0); // <-- This is where
// the processor hangs, because that the SPI peripheral is disabled
// (SPIENS equals 0), which makes TDRE equal to 0 forever.
}
Questions :
-
Qu'est-ce qui fait que le périphérique SPI est désactivé lors de l'écriture dans
SPI_TDR
? -
Dois-je dé-commenter la ligne dans
SPI_Write()
qui lit leSPI_RDR
s'inscrire ?
Moyens, la 4ème ligne du code suivant : (La 4ème ligne est à l'origine marquée comme un commentaire)void SPI_Write(AT91S_SPI *spi, unsigned int npcs, unsigned short data) { // Discard contents of RDR register //volatile unsigned int discard = spi->SPI_RDR; /* Send data */ while ((spi->SPI_SR & AT91C_SPI_TXEMPTY) == 0); spi->SPI_TDR = data | SPI_PCS(npcs); while ((spi->SPI_SR & AT91C_SPI_TDRE) == 0); }
-
Y a-t-il un problème avec le code ci-dessus qui transmet 5 octets de données ?
Veuillez noter :
-
Le numéro de ligne du NPCS. 3 est une ligne GPIO (c'est-à-dire en mode PIO), et n'est pas contrôlée par le contrôleur SPI. Je contrôle cette ligne moi-même dans le code, en activant le pin ChipSelect#3 (NPCS3) quand c'est nécessaire. La raison pour laquelle je fais cela est que des problèmes sont survenus lorsque j'ai essayé de laisser le contrôleur SPI contrôler cette broche.
-
Je n'ai pas utilisé le contrôleur PDC/DMA et je préfère ne pas l'utiliser.
-
Je n'ai pas réinitialisé le périphérique SPI deux fois, parce que l'errata dit de le réinitialiser deux fois seulement si je fais un reset - ce que je ne fais pas. Je cite l'errata :
Si une réinitialisation logicielle (SWRST dans le registre de contrôle SPI) est effectuée, le SPI peut ne pas fonctionner. correctement (l'horloge est activée avant la sélection de puce).
Résolution du problème/contournement
Le champ du registre de contrôle SPI, SWRST (Software Reset) doit être écrit deux fois pour être corrigé. correctement. -
J'ai remarqué que parfois si je mets un délai avant l'écriture dans le fichier
SPI_TDR
registre (enSPI_Write()
), alors le code fonctionne parfaitement et la communication réussit.
Liens utiles :
- Série AT91SAM7X Préliminaire.pdf
- Logiciels/librairies ATMEL
- spi.c de la bibliothèque d'Atmel
- spi.h de la bibliothèque d'Atmel
Un exemple d'initialisation du SPI et d'exécution d'un transfert de 5 octets serait très apprécié et utile.