by nlc » Wed May 30, 2007 12:00 am
Je n'ai pas regardé ton code, mais depuis le debut de la semaine je fais joujou avec une carte d'evaluation R8C/17, et aujourd'hui j'ai justement mis en route l'uart0.
Voici mes sources, attention, ca va paraitre compliqué car l'emission et la reception sont buffeurisés.
Fichier uart0.c :
#include "ior8c17.h"
#include "def.h"
// Definition de la frequence de l'horloge
#define FREQ 20000000
// Definition de la taille des buffers, attention, doivent etre multiple de ^2,
// soit 2 4 8 16 32 64 128 ou 256
#define UART0_RECEIVE_BUFFER_SIZE 32
#define UART0_SEND_BUFFER_SIZE 32
// Definition de la priorité des interruption emission et reception
#define TX_INTERRUPT_PRIORITY 1 // Interruption d'emission peu prioritaire
#define RX_INTERRUPT_PRIORITY 7 // Interruption de reception tres prioritaire
// Calcul de la base du baud rate
#define BAUD_BASE FREQ/16
// Definition des variables des buffers
static BYTE receiveBuffer[UART0_RECEIVE_BUFFER_SIZE]; // Buffer de reception
static BYTE receiveBufferIn; // Index pour le buffer tournant, octet recu
static BYTE receiveBufferOut; // Index pour le buffer tournant, octet lu
static BYTE sendBuffer[UART0_SEND_BUFFER_SIZE]; // Buffer d'emission
static BYTE sendBufferIn; // Index pour le buffer tournant, octet envoyé
static BYTE sendBufferOut; // Index pour le buffer tournant, octet parti
// Interruption de reception
__attribute__((interrupt))
void uart0ReceiveInt ( void )
{
// On stocke l'octet dans le buffer
// A revoir pour tester d'eventuelles erreurs dans la transmission
receiveBuffer[receiveBufferIn] = (BYTE)U0RB.word;
// On avance dans le buffer
receiveBufferIn++;
receiveBufferIn &= UART0_RECEIVE_BUFFER_SIZE-1;
}
// Interruption d'emission
__attribute__((interrupt))
void uart0TransmitInt ( void )
{
// S'il n'y a plus rien a envoyer, on devalide les IRQ transmit-end interrupts
if ( sendBufferOut == sendBufferIn )
{ S0TIC.byte = 0;
}
else
{ // Sinon on envoie le prochain octet
U0TB.byte.U0TBL = sendBuffer[sendBufferOut++];
sendBufferOut &= (UART0_SEND_BUFFER_SIZE-1);
}
}
// Calcul du diviseur
static int getBRG ( long baudRate, long prescaler )
{
int brg = 0;
long baudBase = BAUD_BASE;
// Si on a un presacler de 8 ou 32, on divise le baud base par 8 ou 32
if ( prescaler == 8 ) baudBase >>= 3;
if ( prescaler == 32 ) baudBase >>= 5;
// On compte le nombre de fois ou le baudrate rentre dans le baud base (evite une division)
while ( (baudBase-=baudRate) >= 0 )
{ brg++;
}
// On regarde si on doit arrondir au dessus notre resultat
if ( baudBase+(baudRate>>1) >= 0 )
brg++;
// On retire 1, comme specifié dans la doc
brg--;
return( brg );
}
// Initialisation de l'uart
BYTE _uart0Init ( long speed, char parity, int data, int stopbits )
{
int temp;
// Config du registre U0MR
temp = 0;
switch( data )
{ case 7 : temp += BIT2; break; // Mode 7 bits
case 9 : temp += BIT2+BIT1; break; // Mode 9 bits
case 8 :
default: temp += BIT2+BIT0; break; // Mode 8 bits par defaut
}
if ( stopbits == 2 ) temp += BIT4;
switch( parity )
{ case 'E' : temp += BIT6+BIT5; break; // Parité impaire
case 'O' : temp += BIT6; break; // Parité paire
}
U0MR.byte = (BYTE)temp;
// Config du registre U0CO et du registre U0BRG
U0C0.byte = 0; // Sortie CMOS, pas de prescaler
if ( (temp=getBRG( speed, 0 )) > 255 )
{ U0C0.byte = BIT0; // Sortie CMOS, prescaler de 8
if ( (temp=getBRG( speed, 8 )) > 255 )
{ U0C0.byte = BIT1; // Sortie CMOS, prescaler de 32
temp=getBRG( speed, 32 );
}
}
U0BRG = (BYTE)temp;
// Config du registre U0C1
U0C1.byte = 0x05; // On active l'emission et la reception
// Config du registre UCON
UCON.byte = 0x00;
// Initialisation des index d'emission/reception
receiveBufferIn = receiveBufferOut = 0;
sendBufferIn = sendBufferOut = 0;
// On active les interruptions reception
S0RIC.byte = RX_INTERRUPT_PRIORITY;
// On passe la broche Tx en sortie
P1.bit.P1_4 = 1; // Tx a 1
PD1.bit.PD1_4 = 1; // Tx en sortie
return( TRUE );
}
// Envoi d'un octet, gestion bufferisée
BYTE _uart0Send( unsigned char value )
{
// Si le buffer est plein, pas la peine de continuer
if ( ((sendBufferIn+1) & (UART0_SEND_BUFFER_SIZE-1) ) == sendBufferOut )
return( FALSE );
// On place l'octet dans le buffer
sendBuffer[sendBufferIn] = value;
sendBufferIn++;
sendBufferIn &= (UART0_SEND_BUFFER_SIZE-1);
// Si l'interruption transmission n'est pas validée, on envoie un octet et on la valide
if ( (S0TIC.byte&0x07) == 0 )
{ U0TB.byte.U0TBL = sendBuffer[sendBufferOut++];
sendBufferOut &= (UART0_SEND_BUFFER_SIZE-1);
S0TIC.byte = TX_INTERRUPT_PRIORITY;
}
return( TRUE );
}
// Envoi d'un octet sans passer par le buffer
BYTE _uart0SendDirect ( BYTE value )
{ if ( U0C1.bit.TI )
{ U0TB.byte.U0TBL = value;
return( TRUE );
}
return( FALSE );
}
// Lecture des octets recu
BYTE _uart0Receive( BYTE* value )
{ if ( receiveBufferIn != receiveBufferOut )
{ *value = receiveBuffer[receiveBufferOut];
receiveBufferOut++;
receiveBufferOut &= (UART0_RECEIVE_BUFFER_SIZE-1);
return( TRUE );
}
return( FALSE );
}
// On vide les buffers d'emission et reception
void _uart0Emptying( void )
{ receiveBufferIn = receiveBufferOut = 0;
sendBufferIn = sendBufferOut = 0;
}
Fichier main.c d'exemple :
int main ( void )
{
_uart0Init ( 9600, 'N', 8, 1 );
while ( 1 )
{ BYTE c;
if ( _uart0Receive( &c ) == TRUE )
_uart0Send( c );
}
return 0;
}
Note :
Je travaille sous linux et j'utilise le compilateur GCC pour M16, c'est pour ca que les nom de registres vous paraitront aussi un peu bizarre. Il faut les modifier a votre sauce pour que ca compile. Il ne faut pas oublier aussi de configurer les vecteurs d'IT relatifs a l'uart 0 !!
Du fait que tout est bufferisé, lorsqu'on envoie une trame par exemple, ce n'est pas bloquant et on a la main de suite pour faire autre chose.