mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik UART am LPC2103


Autor: Mike (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich versuche jetzt schon eine ganze Weile einen interrupt basierten uart 
treiber auf meinem lpc2103 zu implementieren. Ich habe schon diverse 
Codebeispiele durchgeschaut und mich durch die Datenblätter gewälzt, 
aber es will einfach nicht stabil laufen. Ab und zu wird bei unten 
angehängtem Beispiel überhaupt nichts ausgegeben, manchmal funktioniert 
es eine Weile und irgendwann bleibt es hängen. Es wäre echt super wenn 
mir jemand helfen könnte.
//main.c

/** include files **/
#include <NXP\iolpc2103.h>
#include <intrinsics.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include "main.h"
#include "uart.h"
#include "macros.h"
#include "interrupts.h"
#include "timer.h"

//System initialization
void Init(void);

void main(void)
{
  uint8_t Buffer[100];
  uint8_t* pBuffer;
  uint32_t Size,RxTranSize,TxTranSize;
  
  __disable_interrupt();
  //System Init
  Init();
  //Init VIC
  VIC_Init();
  timer_init();
  uart0_init(19200UL, 0);
  __enable_interrupt();
  //Enable Fast GPIO
  SCS = 1;
 
  while(1)
  {
    pBuffer = Buffer;
    RxTranSize = uart0_read(pBuffer,Size);
    TxTranSize = uart0_write(pBuffer,RxTranSize);  
  }
}

//System initialization
void Init(void)
{
  //Disabel Memory Accelerator Module
  MAMCR_bit.MODECTRL = 0;
  //Set fetch cycles
#if CCLK < 20000000
  MAMTIM_bit.CYCLES = 1;
#elif CCLK < 40000000
  MAMTIM_bit.CYCLES = 2;
#else
  MAMTIM_bit.CYCLES = 3;
#endif
  //Here MAM can be enabled
  MAMCR_bit.MODECTRL = 0; //MAM is disabled
  //Disable PLL
  PLLCON = 0;
  // Write Feed
  PLLFEED = 0xAA;
  PLLFEED = 0x55;
  //Set MSEL and PSEL
  PLLCFG = PLL_M_VAL | (PLL_P_VAL<<5);  //PLL 14,7456*4 = 58,9824MHz
  // Write Feed
  PLLFEED = 0xaa;
  PLLFEED = 0x55;
  // Enable PLL, disconnected
  PLLCON = 1;       
  // Write Feed
  PLLFEED = 0xaa;
  PLLFEED = 0x55;
  //Set peripherial clock
  APBDIV = APBDIV_VAL;
  //Wait PLL Lock
  while(!PLLSTAT_bit.PLOCK);
  // connect PLL
  PLLCON = 3;       
  // Write Feed
  PLLFEED = 0xaa;
  PLLFEED = 0x55; 
}

Die Uart Initialisierung sieht folgendermaßen aus:
//uart.c
#include <NXP\iolpc2103.h>
#include <stdlib.h>
#include <intrinsics.h>
#include "main.h"
#include "uart.h"
#include "interrupts.h"
#include <yfuns.h>

/** local definitions **/
#define UART_FIFO_SIZE 200

typedef struct _UartFifo_t
{
  uint32_t PushIndx;
  uint32_t PopIndx;
  uint8_t  Buffer[UART_FIFO_SIZE];
} UartFifo_t, *pUartFifo_t;

pUartFifo_t pUart0RxFifo; // Pointer to a FIFO Buffer of the UART0 Receive
pUartFifo_t pUart0TxFifo; // Pointer to a FIFO Buffer of the UART0 Transmit

// Hold UART0 Events (PE, BI, FE, OE)
UartLineEvents_t Uart0LineEvents;

/*************************************************************************
 * Function Name: FifoPush
 * Parameters: pUartFifo_t Fifo, uint8_t Data
 *
 * Return: uint8_t
 *
 * Description: Push a char in a FIFO. Return 1 when push is successful
 *  or 0 when the FIFO is full.
 *
 *************************************************************************/
static uint8_t FifoPush(pUartFifo_t Fifo, uint8_t Data)
{
  uint32_t IndxTmp;

  // calculate next push index
  IndxTmp = Fifo->PushIndx + 1;
  IndxTmp = IndxTmp % UART_FIFO_SIZE;

  // Check FIFO state
  if (IndxTmp == Fifo->PopIndx)
  {
    // The FIFO is full
    return(0);
  }
  // Push the data
  Fifo->Buffer[Fifo->PushIndx] = Data;
  // Updating the push's index
  Fifo->PushIndx = IndxTmp;
  return(1);
}

/*************************************************************************
 * Function Name: FifoPop
 * Parameters: pUartFifo_t Fifo, uint8_t Data
 *
 * Return: uint8_t
 *
 * Description: Pop a char from a FIFO. Return 1 when pop is successful
 *  or 0 when the FIFO is empty.
 *
 *************************************************************************/
static uint8_t FifoPop(pUartFifo_t Fifo, uint8_t* pData)
{
  uint32_t IndxTmp;
  // Check FIFO state
  if (Fifo->PushIndx == Fifo->PopIndx)
  {
    // The FIFO is empty
    return(0);
  }
  // Calculate the next pop index
  IndxTmp = Fifo->PopIndx + 1;
  IndxTmp = IndxTmp % UART_FIFO_SIZE;
  // Pop the data
  *pData = Fifo->Buffer[Fifo->PopIndx];
  // Updating of the pop's index
  Fifo->PopIndx = IndxTmp;
  return(1);
}

/*************************************************************************
 * Function Name: Uart0Isr
 * Parameters: none
 *
 * Return: none
 *
 * Description: UART 0 interrupt routine
 *
 *************************************************************************/
static 
void uart0_isr(void)
{
  uint32_t UartIntId = U0IIR, LineStatus, Counter;
  uint8_t Data;
  // Recognize the interrupt event
  switch (UartIntId & 0xF)
  {
  case RLS_INTR_ID: // Receive Line Status
  case CDI_INTR_ID: // Character Time-out Indicator
  case RDA_INTR_ID: // Receive Data Available
    // Read the line state of the UART
    LineStatus = U0LSR;
    do
    {
      if(LineStatus & RLS_OverrunError)
      {
        // Overrun Error
        Uart0LineEvents.bOE = 1;
      }
      Data = U0RBR;
      if (LineStatus & RLS_BreakInterruptr)
      {
        // Break Indicator
        Uart0LineEvents.bBI = 1;
      }
      else if (LineStatus & RLS_FramingError)
      {
        // Framing Error
        Uart0LineEvents.bFE = 1;
      }
      else if (LineStatus & RLS_ParityError)
      {
        // Parity Error
        Uart0LineEvents.bPE = 1;
      }
      // Push a new data into the receiver buffer
      if(!FifoPush(pUart0RxFifo,Data))
      {
        // the FIFO is full
        Uart0LineEvents.bOE = 1;
        break;
      }
      // Read the line state of the UART
      LineStatus = U0LSR;
    }
    while(LineStatus & RLS_ReceiverDataReady); // Is the hardware FIFO empty?
    break;
  case THRE_INTR_ID:  // THRE Interrupt
    // Tx UART FIFO size - 1
    // Fill whole hardware transmit FIFO
    for (Counter = 15; Counter; --Counter)
    {
      // Pop a data from the transmit buffer
      if(!FifoPop(pUart0TxFifo,&Data))
      {
        // The tx software FIFO is empty
        break;
      }
      U0THR = Data;
    }
    break;
  }
}

/*************************************************************************
 * Function Name: UartInit
 * Parameters: UartNum_t Uart, uint32_t IrqSlot, UartMode_t UartMode
 *
 * Return: uint8_t
 *
 * Description: Init UART
 *
 *************************************************************************/
uint8_t uart0_init(uint32_t Baudrate, uint32_t IrqSlot)
{
  volatile uint8_t Tmp;
  
  pUart0RxFifo = (pUartFifo_t)malloc(sizeof(UartFifo_t));
  if(!pUart0RxFifo)
  {
    return(0);
  }
  pUart0TxFifo = (pUartFifo_t)malloc(sizeof(UartFifo_t));
  if(!pUart0TxFifo)
  {
    free(pUart0RxFifo);
    return(0);
  }
  // Init receive and transmit FIFOs
  pUart0RxFifo->PopIndx = pUart0RxFifo->PushIndx = 0;
  pUart0TxFifo->PopIndx = pUart0TxFifo->PushIndx = 0;

  PCONP_bit.PCUART0 = 1;    // Enable UART0
  PINSEL0_bit.P0_0 = 1;     //Uart TX function select
  PINSEL0_bit.P0_1 = 1;     //Uart RX function select

  U0LCR = 0x03; // Word Length =8, no parity , 1 stop
  U0FDR_bit.MULVAL = 1;     //set fractional divider register multiplier to 1
  U0FDR_bit.DIVADDVAL = 0;  //disable fractional divider (this should change for other baudrates 
  
  U0LCR_bit.DLAB = 1;       //Devisor Latch Access enabled
  U0DLL = ((PCLK/16)/Baudrate)%256;  //configure divisor latch register lsb..
  U0DLM = ((PCLK/16)/Baudrate)/256;  //..and msb
  U0LCR_bit.DLAB = 0;           //Clear Devisor Latch Access bit
  U0FCR = 0x03;//0x7;  // Enable and Clear the UART0 FIFO, Set RX FIFO interrupt level - 1 char
 
  U0TER_bit.TXEN = 1;   // Transmit enable
  Tmp = U0IER;  // Clear pending interrupts
  U0IER = 0x07; // enable RBR Interrupt, THRE Interrupt, RX Line Status Interrupt
    
  Install_IRQ(VIC_UART0, uart0_isr, IrqSlot); //Install Interrupt
  return(1);
}


/*************************************************************************
 * Function Name: uart0_read
 * Parameters:  uint8_t* pBuffer, uint32_t BufferSize
 *
 * Return: uint32_t
 *
 * Description: Read received data from UART0.
 *              Return number of readied characters
 *
 *************************************************************************/
uint32_t uart0_read(uint8_t* pBuffer, uint32_t BufferSize)
{
  uint32_t Count;
  for (Count = 0; Count < BufferSize; ++Count)
  {
    if(!FifoPop(pUart0RxFifo,pBuffer+Count))
    {
      break;
    }
  }
  return(Count);
}

/*************************************************************************
 * Function Name: UartWrite
 * Parameters:  UartNum_t Uart, uint8_t* pBuffer, uint32_t BufferSize
 *
 * Return: uint32_t
 *
 * Description: Write a data to UART. Return number of successful
 *  transmitted bytes
 *
 *************************************************************************/
uint32_t uart0_write(uint8_t* pBuffer, uint32_t BufferSize)
{
  uint32_t Count = 0;

  if(BufferSize != 0)
  {
    volatile uint8_t* pUartTxReg;
    __disable_interrupt();
    //TX FIFO is empty
    if((pUart0TxFifo->PushIndx == pUart0TxFifo->PopIndx))
    {
      pUartTxReg = (uint8_t*)&U0THR;
      if(U0LSR_bit.THRE)
      {
        *pUartTxReg = *pBuffer;
        ++Count;
      }
    }
    for ( ; Count < BufferSize; ++Count)
    {
      if(!FifoPush(pUart0TxFifo,*(pBuffer+Count)))
      {
        break;
      }
    }
   __enable_interrupt();
  }
  return(Count);
}

/*************************************************************************
 * Function Name: uart0_getUartLineEvents
 * Parameters:  
 *
 * Return: UartLineEvents_t
 *
 * Description: Get Uart Line events (PE, OE, FE, BI)
 *
 *************************************************************************/
UartLineEvents_t uart0_getUartLineEvents()
{
  UartLineEvents_t  LineEvents;
  LineEvents.Data = Uart0LineEvents.Data;
  return(LineEvents);
}

und die Interrupts initialisiere ich hier:
//interrupts.c
/** include files **/
#include <nxp/iolpc2103.h>
/** local definitions **/
//Number of Interrupt Sources
#define INT_NUMBERS   32
//IRQ priority levesl
#define VIC_CHANNELS  16
void DefVectISR (void);
static void (* fiq_isr)(void);
/** public functions **/
/*************************************************************************
 * Function Name: VIC_Init
 *
 * Parameters: None
 *
 * Return:  None
 *
 * Description: Inits the Vectiored Interrupt Controler
 *              Clears and Disables all interrupts. All interrupts are set
 *              to IRQ mode. 
 *
 *************************************************************************/
void VIC_Init(void)
{
unsigned int * VectAddr = (unsigned int *)&VICVectAddr0;
unsigned int * VectCntl = (unsigned int *)&VICVectCntl0;

  //Disable all interrupts
  VICIntEnClear = 0xFFFFFFFF;
  //Clear Software Interrupts
  VICSoftIntClear = 0xFFFFFFFF;
  //Write to VicVectAddr register
  VICVectAddr = 0;
  //Set all to IRQ
  VICIntSelect = 0;
  //Set Default Vector Address to NULL
  VICDefVectAddr = 0;
  //Set all the vector addresses to NULL
  //Disable all IRQ channels
  for ( unsigned int i = 0; i < VIC_CHANNELS; i++ )
  {
    VectAddr[i] = 0x0;
    VectCntl[i] = 0x0;
  }
}
/*************************************************************************
 * Function Name: Instal_IRQ
 * Parameters:Interrupt Number, ISR pointer, VIC channel
 *
 * Return: None
 *
 * Description: Installs Interrup Serice Routine at selected VIC channel 
 *              Enables the interrupt. This function can be used for enabling
 *              a default interrupt if it is called with channel >= VIC_CHANNELS
 *************************************************************************/
void Install_IRQ(unsigned int IntNumber, void (*ISR)(void), unsigned int channel)
{
unsigned int * VectAddr = (unsigned int *)&VICVectAddr0;
unsigned int * VectCntl = (unsigned int *)&VICVectCntl0;

#ifdef DEBUG
  if (INT_NUMBERS < IntNumber)
  {//Wrong Int Number
    while(1);
  }
#endif
  //Disable Interrupt
  VICIntEnClear = 1<<IntNumber;
  
  if(VIC_CHANNELS > channel)
  {//Vectired IRQ
    //Set interrupt Vector
    VectAddr[channel] = (unsigned int)ISR;
    //Set Int Number and enable the channel
    VectCntl[channel] = IntNumber | (1<<5);
  }
  else
  {//Non-vectired IRQ
    //Install ISR for non vectored IRQ
    VICDefVectAddr = (unsigned int)DefVectISR ;
  }
  //Enable Interrupt
  VICIntEnable = 1 << IntNumber;
}
/*************************************************************************
 * Function Name: Install_FIQ
 * Parameters: Interrupt Number
 *
 * Return:  None
 *
 * Description: Sets Interrup in FIQ mode and enables it
 *
 *************************************************************************/
void Install_FIQ(unsigned int IntNumber,   void (*ISR)(void))
{
  //Disable Interrupt
  VICIntEnClear = 1<<IntNumber;
  //Set FIQ mode
  VICIntSelect |= 1<<IntNumber;
  //Set interrupt Vector
  fiq_isr = ISR;
  //Enable Interrupt
  VICIntEnable = 1 << IntNumber;
} 

/*************************************************************************
 * Function Name: IRQ_Handler
 * Parameters:None
 *
 * Return:None
 *
 * Description:The IRQ Handler
 *
 *************************************************************************/
__irq __arm void IRQ_Handler (void)
{
void (* IntVector)(void);

  IntVector = (void (*)(void)) VICVectAddr;    //Read Interrup Vector
  (* IntVector)();                             //Call ISR
  
  VICVectAddr = 0;                 //Dummy write to Vector address register
}
/*************************************************************************
 * Function Name: FIQ_Handler
 * Parameters:None
 *
 * Return:None
 *
 * Description:The FIQ Handler
 *
 *************************************************************************/
__fiq __arm void FIQ_Handler(void)
{
  (* fiq_isr)();                             //Call ISR
}
/*************************************************************************
 * Function Name: DefVectISR
 * Parameters:None
 *
 * Return:None
 *
 * Description:The Non-vectored IRQ ISR
 *
 *************************************************************************/
/** private functions **/
static void DefVectISR (void)
{//Put Code of NON vectored ISR here
  return;
}

MfG,

Mike

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erst lesen, dann schreiben:

Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang


Peter

Autor: wp (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

probiers mal mit den Beispielen auf

http://www.siwawi.arubi.uni-kl.de/avr_projects/arm...

Ich habe den LPC2368 mit dem Beispiel
GPIO, UART and interrupt example for the NXP LPC2378 / NXP LPC2368
getestet, funktioniert bei mir ganz gut.

Mfg
Walter

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.