Forum: Mikrocontroller und Digitale Elektronik UART am LPC2103


von Mike (Gast)


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.
1
//main.c
2
3
/** include files **/
4
#include <NXP\iolpc2103.h>
5
#include <intrinsics.h>
6
#include <stdio.h>
7
#include <string.h>
8
#include <stdlib.h>
9
#include <ctype.h>
10
11
#include "main.h"
12
#include "uart.h"
13
#include "macros.h"
14
#include "interrupts.h"
15
#include "timer.h"
16
17
//System initialization
18
void Init(void);
19
20
void main(void)
21
{
22
  uint8_t Buffer[100];
23
  uint8_t* pBuffer;
24
  uint32_t Size,RxTranSize,TxTranSize;
25
  
26
  __disable_interrupt();
27
  //System Init
28
  Init();
29
  //Init VIC
30
  VIC_Init();
31
  timer_init();
32
  uart0_init(19200UL, 0);
33
  __enable_interrupt();
34
  //Enable Fast GPIO
35
  SCS = 1;
36
 
37
  while(1)
38
  {
39
    pBuffer = Buffer;
40
    RxTranSize = uart0_read(pBuffer,Size);
41
    TxTranSize = uart0_write(pBuffer,RxTranSize);  
42
  }
43
}
44
45
//System initialization
46
void Init(void)
47
{
48
  //Disabel Memory Accelerator Module
49
  MAMCR_bit.MODECTRL = 0;
50
  //Set fetch cycles
51
#if CCLK < 20000000
52
  MAMTIM_bit.CYCLES = 1;
53
#elif CCLK < 40000000
54
  MAMTIM_bit.CYCLES = 2;
55
#else
56
  MAMTIM_bit.CYCLES = 3;
57
#endif
58
  //Here MAM can be enabled
59
  MAMCR_bit.MODECTRL = 0; //MAM is disabled
60
  //Disable PLL
61
  PLLCON = 0;
62
  // Write Feed
63
  PLLFEED = 0xAA;
64
  PLLFEED = 0x55;
65
  //Set MSEL and PSEL
66
  PLLCFG = PLL_M_VAL | (PLL_P_VAL<<5);  //PLL 14,7456*4 = 58,9824MHz
67
  // Write Feed
68
  PLLFEED = 0xaa;
69
  PLLFEED = 0x55;
70
  // Enable PLL, disconnected
71
  PLLCON = 1;       
72
  // Write Feed
73
  PLLFEED = 0xaa;
74
  PLLFEED = 0x55;
75
  //Set peripherial clock
76
  APBDIV = APBDIV_VAL;
77
  //Wait PLL Lock
78
  while(!PLLSTAT_bit.PLOCK);
79
  // connect PLL
80
  PLLCON = 3;       
81
  // Write Feed
82
  PLLFEED = 0xaa;
83
  PLLFEED = 0x55; 
84
}

Die Uart Initialisierung sieht folgendermaßen aus:
1
//uart.c
2
#include <NXP\iolpc2103.h>
3
#include <stdlib.h>
4
#include <intrinsics.h>
5
#include "main.h"
6
#include "uart.h"
7
#include "interrupts.h"
8
#include <yfuns.h>
9
10
/** local definitions **/
11
#define UART_FIFO_SIZE 200
12
13
typedef struct _UartFifo_t
14
{
15
  uint32_t PushIndx;
16
  uint32_t PopIndx;
17
  uint8_t  Buffer[UART_FIFO_SIZE];
18
} UartFifo_t, *pUartFifo_t;
19
20
pUartFifo_t pUart0RxFifo; // Pointer to a FIFO Buffer of the UART0 Receive
21
pUartFifo_t pUart0TxFifo; // Pointer to a FIFO Buffer of the UART0 Transmit
22
23
// Hold UART0 Events (PE, BI, FE, OE)
24
UartLineEvents_t Uart0LineEvents;
25
26
/*************************************************************************
27
 * Function Name: FifoPush
28
 * Parameters: pUartFifo_t Fifo, uint8_t Data
29
 *
30
 * Return: uint8_t
31
 *
32
 * Description: Push a char in a FIFO. Return 1 when push is successful
33
 *  or 0 when the FIFO is full.
34
 *
35
 *************************************************************************/
36
static uint8_t FifoPush(pUartFifo_t Fifo, uint8_t Data)
37
{
38
  uint32_t IndxTmp;
39
40
  // calculate next push index
41
  IndxTmp = Fifo->PushIndx + 1;
42
  IndxTmp = IndxTmp % UART_FIFO_SIZE;
43
44
  // Check FIFO state
45
  if (IndxTmp == Fifo->PopIndx)
46
  {
47
    // The FIFO is full
48
    return(0);
49
  }
50
  // Push the data
51
  Fifo->Buffer[Fifo->PushIndx] = Data;
52
  // Updating the push's index
53
  Fifo->PushIndx = IndxTmp;
54
  return(1);
55
}
56
57
/*************************************************************************
58
 * Function Name: FifoPop
59
 * Parameters: pUartFifo_t Fifo, uint8_t Data
60
 *
61
 * Return: uint8_t
62
 *
63
 * Description: Pop a char from a FIFO. Return 1 when pop is successful
64
 *  or 0 when the FIFO is empty.
65
 *
66
 *************************************************************************/
67
static uint8_t FifoPop(pUartFifo_t Fifo, uint8_t* pData)
68
{
69
  uint32_t IndxTmp;
70
  // Check FIFO state
71
  if (Fifo->PushIndx == Fifo->PopIndx)
72
  {
73
    // The FIFO is empty
74
    return(0);
75
  }
76
  // Calculate the next pop index
77
  IndxTmp = Fifo->PopIndx + 1;
78
  IndxTmp = IndxTmp % UART_FIFO_SIZE;
79
  // Pop the data
80
  *pData = Fifo->Buffer[Fifo->PopIndx];
81
  // Updating of the pop's index
82
  Fifo->PopIndx = IndxTmp;
83
  return(1);
84
}
85
86
/*************************************************************************
87
 * Function Name: Uart0Isr
88
 * Parameters: none
89
 *
90
 * Return: none
91
 *
92
 * Description: UART 0 interrupt routine
93
 *
94
 *************************************************************************/
95
static 
96
void uart0_isr(void)
97
{
98
  uint32_t UartIntId = U0IIR, LineStatus, Counter;
99
  uint8_t Data;
100
  // Recognize the interrupt event
101
  switch (UartIntId & 0xF)
102
  {
103
  case RLS_INTR_ID: // Receive Line Status
104
  case CDI_INTR_ID: // Character Time-out Indicator
105
  case RDA_INTR_ID: // Receive Data Available
106
    // Read the line state of the UART
107
    LineStatus = U0LSR;
108
    do
109
    {
110
      if(LineStatus & RLS_OverrunError)
111
      {
112
        // Overrun Error
113
        Uart0LineEvents.bOE = 1;
114
      }
115
      Data = U0RBR;
116
      if (LineStatus & RLS_BreakInterruptr)
117
      {
118
        // Break Indicator
119
        Uart0LineEvents.bBI = 1;
120
      }
121
      else if (LineStatus & RLS_FramingError)
122
      {
123
        // Framing Error
124
        Uart0LineEvents.bFE = 1;
125
      }
126
      else if (LineStatus & RLS_ParityError)
127
      {
128
        // Parity Error
129
        Uart0LineEvents.bPE = 1;
130
      }
131
      // Push a new data into the receiver buffer
132
      if(!FifoPush(pUart0RxFifo,Data))
133
      {
134
        // the FIFO is full
135
        Uart0LineEvents.bOE = 1;
136
        break;
137
      }
138
      // Read the line state of the UART
139
      LineStatus = U0LSR;
140
    }
141
    while(LineStatus & RLS_ReceiverDataReady); // Is the hardware FIFO empty?
142
    break;
143
  case THRE_INTR_ID:  // THRE Interrupt
144
    // Tx UART FIFO size - 1
145
    // Fill whole hardware transmit FIFO
146
    for (Counter = 15; Counter; --Counter)
147
    {
148
      // Pop a data from the transmit buffer
149
      if(!FifoPop(pUart0TxFifo,&Data))
150
      {
151
        // The tx software FIFO is empty
152
        break;
153
      }
154
      U0THR = Data;
155
    }
156
    break;
157
  }
158
}
159
160
/*************************************************************************
161
 * Function Name: UartInit
162
 * Parameters: UartNum_t Uart, uint32_t IrqSlot, UartMode_t UartMode
163
 *
164
 * Return: uint8_t
165
 *
166
 * Description: Init UART
167
 *
168
 *************************************************************************/
169
uint8_t uart0_init(uint32_t Baudrate, uint32_t IrqSlot)
170
{
171
  volatile uint8_t Tmp;
172
  
173
  pUart0RxFifo = (pUartFifo_t)malloc(sizeof(UartFifo_t));
174
  if(!pUart0RxFifo)
175
  {
176
    return(0);
177
  }
178
  pUart0TxFifo = (pUartFifo_t)malloc(sizeof(UartFifo_t));
179
  if(!pUart0TxFifo)
180
  {
181
    free(pUart0RxFifo);
182
    return(0);
183
  }
184
  // Init receive and transmit FIFOs
185
  pUart0RxFifo->PopIndx = pUart0RxFifo->PushIndx = 0;
186
  pUart0TxFifo->PopIndx = pUart0TxFifo->PushIndx = 0;
187
188
  PCONP_bit.PCUART0 = 1;    // Enable UART0
189
  PINSEL0_bit.P0_0 = 1;     //Uart TX function select
190
  PINSEL0_bit.P0_1 = 1;     //Uart RX function select
191
192
  U0LCR = 0x03; // Word Length =8, no parity , 1 stop
193
  U0FDR_bit.MULVAL = 1;     //set fractional divider register multiplier to 1
194
  U0FDR_bit.DIVADDVAL = 0;  //disable fractional divider (this should change for other baudrates 
195
  
196
  U0LCR_bit.DLAB = 1;       //Devisor Latch Access enabled
197
  U0DLL = ((PCLK/16)/Baudrate)%256;  //configure divisor latch register lsb..
198
  U0DLM = ((PCLK/16)/Baudrate)/256;  //..and msb
199
  U0LCR_bit.DLAB = 0;           //Clear Devisor Latch Access bit
200
  U0FCR = 0x03;//0x7;  // Enable and Clear the UART0 FIFO, Set RX FIFO interrupt level - 1 char
201
 
202
  U0TER_bit.TXEN = 1;   // Transmit enable
203
  Tmp = U0IER;  // Clear pending interrupts
204
  U0IER = 0x07; // enable RBR Interrupt, THRE Interrupt, RX Line Status Interrupt
205
    
206
  Install_IRQ(VIC_UART0, uart0_isr, IrqSlot); //Install Interrupt
207
  return(1);
208
}
209
210
211
/*************************************************************************
212
 * Function Name: uart0_read
213
 * Parameters:  uint8_t* pBuffer, uint32_t BufferSize
214
 *
215
 * Return: uint32_t
216
 *
217
 * Description: Read received data from UART0.
218
 *              Return number of readied characters
219
 *
220
 *************************************************************************/
221
uint32_t uart0_read(uint8_t* pBuffer, uint32_t BufferSize)
222
{
223
  uint32_t Count;
224
  for (Count = 0; Count < BufferSize; ++Count)
225
  {
226
    if(!FifoPop(pUart0RxFifo,pBuffer+Count))
227
    {
228
      break;
229
    }
230
  }
231
  return(Count);
232
}
233
234
/*************************************************************************
235
 * Function Name: UartWrite
236
 * Parameters:  UartNum_t Uart, uint8_t* pBuffer, uint32_t BufferSize
237
 *
238
 * Return: uint32_t
239
 *
240
 * Description: Write a data to UART. Return number of successful
241
 *  transmitted bytes
242
 *
243
 *************************************************************************/
244
uint32_t uart0_write(uint8_t* pBuffer, uint32_t BufferSize)
245
{
246
  uint32_t Count = 0;
247
248
  if(BufferSize != 0)
249
  {
250
    volatile uint8_t* pUartTxReg;
251
    __disable_interrupt();
252
    //TX FIFO is empty
253
    if((pUart0TxFifo->PushIndx == pUart0TxFifo->PopIndx))
254
    {
255
      pUartTxReg = (uint8_t*)&U0THR;
256
      if(U0LSR_bit.THRE)
257
      {
258
        *pUartTxReg = *pBuffer;
259
        ++Count;
260
      }
261
    }
262
    for ( ; Count < BufferSize; ++Count)
263
    {
264
      if(!FifoPush(pUart0TxFifo,*(pBuffer+Count)))
265
      {
266
        break;
267
      }
268
    }
269
   __enable_interrupt();
270
  }
271
  return(Count);
272
}
273
274
/*************************************************************************
275
 * Function Name: uart0_getUartLineEvents
276
 * Parameters:  
277
 *
278
 * Return: UartLineEvents_t
279
 *
280
 * Description: Get Uart Line events (PE, OE, FE, BI)
281
 *
282
 *************************************************************************/
283
UartLineEvents_t uart0_getUartLineEvents()
284
{
285
  UartLineEvents_t  LineEvents;
286
  LineEvents.Data = Uart0LineEvents.Data;
287
  return(LineEvents);
288
}

und die Interrupts initialisiere ich hier:
1
//interrupts.c
2
/** include files **/
3
#include <nxp/iolpc2103.h>
4
/** local definitions **/
5
//Number of Interrupt Sources
6
#define INT_NUMBERS   32
7
//IRQ priority levesl
8
#define VIC_CHANNELS  16
9
void DefVectISR (void);
10
static void (* fiq_isr)(void);
11
/** public functions **/
12
/*************************************************************************
13
 * Function Name: VIC_Init
14
 *
15
 * Parameters: None
16
 *
17
 * Return:  None
18
 *
19
 * Description: Inits the Vectiored Interrupt Controler
20
 *              Clears and Disables all interrupts. All interrupts are set
21
 *              to IRQ mode. 
22
 *
23
 *************************************************************************/
24
void VIC_Init(void)
25
{
26
unsigned int * VectAddr = (unsigned int *)&VICVectAddr0;
27
unsigned int * VectCntl = (unsigned int *)&VICVectCntl0;
28
29
  //Disable all interrupts
30
  VICIntEnClear = 0xFFFFFFFF;
31
  //Clear Software Interrupts
32
  VICSoftIntClear = 0xFFFFFFFF;
33
  //Write to VicVectAddr register
34
  VICVectAddr = 0;
35
  //Set all to IRQ
36
  VICIntSelect = 0;
37
  //Set Default Vector Address to NULL
38
  VICDefVectAddr = 0;
39
  //Set all the vector addresses to NULL
40
  //Disable all IRQ channels
41
  for ( unsigned int i = 0; i < VIC_CHANNELS; i++ )
42
  {
43
    VectAddr[i] = 0x0;
44
    VectCntl[i] = 0x0;
45
  }
46
}
47
/*************************************************************************
48
 * Function Name: Instal_IRQ
49
 * Parameters:Interrupt Number, ISR pointer, VIC channel
50
 *
51
 * Return: None
52
 *
53
 * Description: Installs Interrup Serice Routine at selected VIC channel 
54
 *              Enables the interrupt. This function can be used for enabling
55
 *              a default interrupt if it is called with channel >= VIC_CHANNELS
56
 *************************************************************************/
57
void Install_IRQ(unsigned int IntNumber, void (*ISR)(void), unsigned int channel)
58
{
59
unsigned int * VectAddr = (unsigned int *)&VICVectAddr0;
60
unsigned int * VectCntl = (unsigned int *)&VICVectCntl0;
61
62
#ifdef DEBUG
63
  if (INT_NUMBERS < IntNumber)
64
  {//Wrong Int Number
65
    while(1);
66
  }
67
#endif
68
  //Disable Interrupt
69
  VICIntEnClear = 1<<IntNumber;
70
  
71
  if(VIC_CHANNELS > channel)
72
  {//Vectired IRQ
73
    //Set interrupt Vector
74
    VectAddr[channel] = (unsigned int)ISR;
75
    //Set Int Number and enable the channel
76
    VectCntl[channel] = IntNumber | (1<<5);
77
  }
78
  else
79
  {//Non-vectired IRQ
80
    //Install ISR for non vectored IRQ
81
    VICDefVectAddr = (unsigned int)DefVectISR ;
82
  }
83
  //Enable Interrupt
84
  VICIntEnable = 1 << IntNumber;
85
}
86
/*************************************************************************
87
 * Function Name: Install_FIQ
88
 * Parameters: Interrupt Number
89
 *
90
 * Return:  None
91
 *
92
 * Description: Sets Interrup in FIQ mode and enables it
93
 *
94
 *************************************************************************/
95
void Install_FIQ(unsigned int IntNumber,   void (*ISR)(void))
96
{
97
  //Disable Interrupt
98
  VICIntEnClear = 1<<IntNumber;
99
  //Set FIQ mode
100
  VICIntSelect |= 1<<IntNumber;
101
  //Set interrupt Vector
102
  fiq_isr = ISR;
103
  //Enable Interrupt
104
  VICIntEnable = 1 << IntNumber;
105
} 
106
107
/*************************************************************************
108
 * Function Name: IRQ_Handler
109
 * Parameters:None
110
 *
111
 * Return:None
112
 *
113
 * Description:The IRQ Handler
114
 *
115
 *************************************************************************/
116
__irq __arm void IRQ_Handler (void)
117
{
118
void (* IntVector)(void);
119
120
  IntVector = (void (*)(void)) VICVectAddr;    //Read Interrup Vector
121
  (* IntVector)();                             //Call ISR
122
  
123
  VICVectAddr = 0;                 //Dummy write to Vector address register
124
}
125
/*************************************************************************
126
 * Function Name: FIQ_Handler
127
 * Parameters:None
128
 *
129
 * Return:None
130
 *
131
 * Description:The FIQ Handler
132
 *
133
 *************************************************************************/
134
__fiq __arm void FIQ_Handler(void)
135
{
136
  (* fiq_isr)();                             //Call ISR
137
}
138
/*************************************************************************
139
 * Function Name: DefVectISR
140
 * Parameters:None
141
 *
142
 * Return:None
143
 *
144
 * Description:The Non-vectored IRQ ISR
145
 *
146
 *************************************************************************/
147
/** private functions **/
148
static void DefVectISR (void)
149
{//Put Code of NON vectored ISR here
150
  return;
151
}

MfG,

Mike

von Peter D. (peda)


Lesenswert?

Erst lesen, dann schreiben:

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


Peter

von wp (Gast)


Lesenswert?

Hallo,

probiers mal mit den Beispielen auf

http://www.siwawi.arubi.uni-kl.de/avr_projects/arm_projects/index.html#lpc_can1

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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.