Forum: Mikrocontroller und Digitale Elektronik Xmega 256a3b Usart sendet immer ASCII 255


von Florian M. (Firma: FZMB GmbH) (florianm)


Lesenswert?

Hallo,

ich habe folgendes Problem:

ich möchte ein Programm zum senden und empfangen von einzelnen Zeichen 
über den Usart eines xmega256a3b nutzen.

Ich benutze ein Testboard "Xmega EVAL-USB-256" von "Boston Android". 
Dort werden auch diverse Codebeispiele zur Verfügung gestellt.

Auf dem genannten Board ist Port F vom xmega mit einem FTDI Chip 
verbunden, und wird dann per USB und entspr. VCP Treiber mit dem PC 
verbunden.

Ich habe das Beispiel "serial echo" compiliert und auf den Chip 
übertragen.

hier ist der betr. Code:
1
#include <stdio.h>
2
#include <avr\io.h>
3
#define F_CPU 32000000UL
4
#include <util\delay.h>
5
6
void Config32MHzClock(void);
7
void UsartWriteChar(unsigned char data);
8
unsigned char UsartReadChar(void);
9
10
int main(void)
11
{
12
  int data;
13
  Config32MHzClock();
14
  CLK.PSCTRL = 0x00; // no division on peripheral clock
15
  PORTCFG.CLKEVOUT = PORTCFG_CLKOUT_PE7_gc;
16
  PORTE.DIR = (1<<7); // clkout
17
18
  // configure PORTF, USARTF0 (PORTF:3=Tx, PORTF:2=Rx) as asynch serial port
19
  // This will connect to the USB-Serial chip on EVAL-USB boards
20
  // For other boards rewrite all occurences of USARTF0 below with USARTE0
21
  // then you can use PORTE:2,3 as asynch serial port (EVAL-01, EVAL-04 boards)
22
  PORTF.DIR |= (1<<3) | (1<<0); // set PORTF:3 transmit pin as output
23
  PORTF.OUT |= (1<<3);          // set PORTF:3 hi 
24
25
  USARTF0.BAUDCTRLA = 34;  // 57600b  (BSCALE=34,BSEL=0)
26
  USARTF0.CTRLB = USART_TXEN_bm | USART_RXEN_bm; // enable tx and rx 
27
28
  while(1)
29
  {
30
    data=UsartReadChar(); // read char
31
  UsartWriteChar(data); // write char
32
  _delay_ms(100);
33
  PORTF.OUT ^= (1<<0); // toggle LED
34
35
  };
36
};
37
38
void UsartWriteChar(unsigned char data)
39
{
40
    USARTF0.DATA = data; // transmit ascii 3 over and over
41
  if(!(USARTF0.STATUS&USART_DREIF_bm))
42
    while(!(USARTF0.STATUS & USART_TXCIF_bm)); // wait for TX complete
43
    USARTF0.STATUS |= USART_TXCIF_bm;  // clear TX interrupt flag
44
};
45
46
unsigned char UsartReadChar(void)
47
{
48
  unsigned char ret;
49
  while(!(USARTF0.STATUS&USART_RXCIF_bm));  // wait for RX complete
50
51
    return USARTF0.DATA;
52
};
53
54
55
void Config32MHzClock(void)
56
{
57
  CCP = CCP_IOREG_gc; //Security Signature to modify clock 
58
  // initialize clock source to be 32MHz internal oscillator (no PLL)
59
  OSC.CTRL = OSC_RC32MEN_bm; // enable internal 32MHz oscillator
60
  while(!(OSC.STATUS & OSC_RC32MRDY_bm)); // wait for oscillator ready
61
  CCP = CCP_IOREG_gc; //Security Signature to modify clock 
62
  CLK.CTRL = 0x01; //select sysclock 32MHz osc
63
};

Benutze ich ein Terminal Programm zum Testen empfange ich unabhängig vom 
eingegebenen Zeichen "ÿ -- Ascii 255".

Hat evtl. jemand eine Idee woran das liegt?

Danke,

Florian

von Krapao (Gast)


Lesenswert?

Teile und Herrsche. Bist du sicher, dass du nicht data falsch 255 
empfängst und richtig zurück sendest?

von Florian M. (Firma: FZMB GmbH) (florianm)


Lesenswert?

Ich hatte schon folgendes getestet:
1
unsigned char data = 'T'; 
2
_delay_ms(100);
3
UsartWriteChar(data); // write char
4
_delay_ms(100);
5
PORTF.OUT ^= (1<<0); // toggle LED

Bringt das selbe Ergebnis...Es wird kein T zurückgesendet, sondern Ascii 
255...

von Carsten W. (eagle38106)


Lesenswert?

Hi!

Probier mal dies hier:

1
//! \brief putchar () replacement
2
//!
3
//! Simple, blocking putchar () replacement.
4
//!
5
//! \param ch                 Character to be sent.
6
7
void PutChar (char ch)
8
{
9
  // Wait until the transmit buffer is free to accept the next character
10
  while ((USARTxx.STATUS & USART_DREIF_bm) == 0x00);
11
  USARTxx.DATA = ch;
12
13
  // Expand a <cr> to a <cr><lf> sequence.
14
  if (ch == '\r')
15
    PutChar ('\n');
16
}

Wahrscheinlich schießt Du die Transmission ab, indem Du das 
Interrupt-Flag setzt!

Gruß
Carsten

von Heiko V. (xmegaman)


Lesenswert?

Hallo Florian,

bist du absolut sicher, dass die Baudrate im Terminal-Programm korrekt 
eingestellt ist ?
Denn bei einer BR, die 4800 oder langsamer ist, wäre jedes vom xmega 
gesendete Zeichen quasi nur das Startbit im Empfangs-Uart, und danach 
kommt nur noch Ruhepegel -> 255.

Frage: Warum das Senden nicht einfach so:
1
void UsartWriteChar(unsigned char data)
2
{
3
    while(!(USARTF0.STATUS & USART_DREIF_bm)); // wait for DRE
4
    USARTF0.DATA = data; // transmit data
5
}
Dann kannst du dir das Warten auf TXCIF sparen und auch das Resetten des 
TXC-Flags.

Gruß

Xmegaman

von Florian M. (Firma: FZMB GmbH) (florianm)


Lesenswert?

Danke für die Antworten,

@ Carsten: habe ich getestet, bringt aber keine Veränderung...immer noch 
ÿ!

@ Xmegaman: habe ich getestet, bringt aber keine Veränderung...immer 
noch ÿ!
Die Baudrate habe ich nochmal überprüft, sollte alles stimmen, habe auch 
noch mal mit 9600 Baud getestet, bringt das gleiche Ergebniss...

Evtl. teste ich mal einen anderen Usart, vielleicht ist ja der FTDI Chip 
hinüber???

von Carsten W. (eagle38106)


Lesenswert?

Test des USB-Seriell-Wandlers:
- FLASH des AVR löschen (Damit alle Pins als Input konfiguriert
  werden
- RX und TX kurzschließen.
- Wenn jetzt Daten übertragen werden, ist der FTDI Chip ok.
- Wenn nicht, dann tauschen.

Die Benutzung irgendwelcher interner Taktgeneratoren in Verbindung mit 
einer seriellen Schnittstelle ist immer ein Risiko! In der Regel sind 
die Abweichungen viel zu groß!

Schließe mal einen 8MHz Quarz an und probiere folgendes:


types.h
1
#ifndef __TYPES_H__
2
#define __TYPES_H__
3
4
5
typedef signed char             tINT8;
6
typedef signed int              tINT16;
7
typedef signed long             tINT32;
8
typedef unsigned char           tUINT8;
9
typedef unsigned int            tUINT16;
10
typedef unsigned long           tUINT32;
11
typedef volatile signed char    tVINT8;
12
typedef volatile signed int     tVINT16;
13
typedef volatile signed long    tVINT32;
14
typedef volatile unsigned char  tVUINT8;
15
typedef volatile unsigned int   tVUINT16;
16
typedef volatile unsigned long  tVUINT32;
17
typedef volatile bool           tVBOOL;
18
19
20
#endif // __TYPES_H__

main.c
1
//! -----------------------------------------------------------------------------------------------
2
//!
3
//!  © Copyright 2011 by
4
//!
5
//!    Carsten Wille
6
//!    Karlstraße 68
7
//!    D-38106 Braunschweig
8
//!
9
//!  All rights reserved.
10
//!
11
//!  Redistribution and use in source and binary forms, with or without modification, are permitted
12
//!  provided that the following conditions are met:
13
//!
14
//!  * Redistributions of source code must retain the above copyright notice, this list of
15
//!    conditions and the following disclaimer.
16
//!  * Redistributions in binary form must reproduce the above copyright notice, this list of
17
//!    conditions and the following disclaimer in the documentation and/or other materials provided
18
//!    with the distribution.
19
//!  * Neither the name of Carsten Wille nor the names of its contributors may be used to
20
//!    endorse or promote products derived from this software without specific prior written
21
//!    permission.
22
//!
23
//!  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
24
//!  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
25
//!  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
26
//!  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
//!  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28
//!  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29
//!  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30
//!  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
//!  POSSIBILITY OF SUCH DAMAGE.
32
//!
33
//! -----------------------------------------------------------------------------------------------
34
35
// Make the necessary adjustments at this point to match with the desired target MCU and clocking.
36
#define F_CPU       32000000UL          // Run with 32MHz after PLL
37
#define USARTxx     USARTC1             // Choose USART C1 as communications port
38
#define USARTport   PORTC               // Matching port for the chosen USART
39
#define USARTtxd    PIN7_bm             // Bit mask of the TxD pin
40
41
#include <avr/eeprom.h>
42
#include <avr/interrupt.h>
43
#include <avr/io.h>
44
#include <avr/pgmspace.h>
45
#include <stdbool.h>
46
47
#include "types.h"
48
49
50
//! \brief Fuses for the .elf-file
51
//!
52
//! The following code lines define the fuses for the .elf-file. There is no more need to set them
53
//! manually during the programming process.
54
//! Fuses of the naked device: 0xFF, 0x00, 0xFF, 0xFE, 0xFF
55
56
FUSES =
57
{
58
  0xFF,     // JTAG User ID
59
  0x0A,     // WDPER set to 8s, no window
60
  0xBE,     // BOOTRST = BOOTLDR, BODPD = BOD enabled continuously during power down
61
  0xFF,     // Reserved byte with no function here.
62
  0xFD,     // ext. Reset enabled, no startup delay, WDT locked and enabled, JTAG I/F disabled
63
  0xE3      // BODACT = BOD enabled continuously, EESAVE on, BODLEVEL = 2.6V
64
};
65
66
67
#if F_CPU != 32000000UL
68
  #error "ERROR: F_CPU must be 32MHz or baud rate generation won't work as designed!"
69
#endif
70
71
#ifndef USARTxx
72
  #error "ERROR: USARTxx must be defined with the correct port!"
73
#endif
74
75
76
//! \brief CCP write helper function written in assembly.
77
//!
78
//! This function is written in assembly because of the time critical operation of writing to
79
//! the registers. (From clksys_driver.c of the Atmel application note AVR1003)
80
//!
81
//! \param address A pointer to the address to write to.
82
//! \param value   The value to put in to the register.
83
84
void CCPWrite (tVUINT8* address, tUINT8 value)
85
{
86
  tVUINT8* tmpAddr = address;
87
88
#ifdef RAMPZ
89
  RAMPZ = 0;
90
#endif
91
  asm volatile
92
  (
93
    "movw r30,  %0"      "\n\t"
94
    "ldi  r16,  %2"      "\n\t"
95
    "out   %3, r16"      "\n\t"
96
    "st     Z,  %1"      "\n\t"
97
    :
98
    : "r" (tmpAddr), "r" (value), "M" (CCP_IOREG_gc), "i" (&CCP)
99
    : "r16", "r30", "r31"
100
  );
101
}
102
103
104
//! \brief Check for an available character.
105
//!
106
//! Check for an available character in the receive buffer.
107
//!
108
//! \return True, if the flag is set.
109
110
bool CharAvailable ()
111
{
112
  return ((USARTxx.STATUS & USART_RXCIF_bm) != 0x00);
113
}
114
115
116
//! \brief getchar () replacement
117
//!
118
//! Simple, blocking getchar () replacement routine.
119
//!
120
//! \return Character, read from the serial interface of USART C1
121
122
char GetChar ()
123
{
124
  // Wait until something is ready to be read from the receive buffer.
125
  while ((USARTxx.STATUS & USART_RXCIF_bm) == 0x00)
126
  {
127
    // Reset watchdog timer while waiting for the next character.
128
    asm ("wdr");
129
  }
130
  return USARTxx.DATA;
131
}
132
133
134
//! \brief putchar () replacement
135
//!
136
//! Simple, blocking putchar () replacement.
137
//!
138
//! \param ch                 Character to be sent.
139
140
void PutChar (char ch)
141
{
142
  // Wait until the transmit buffer is free to accept the next character
143
  while ((USARTxx.STATUS & USART_DREIF_bm) == 0x00)
144
  {
145
    // Reset watchdog timer while waiting for the buffer to be free again.
146
    asm ("wdr");
147
  }
148
  USARTxx.DATA = ch;
149
150
  // Expand a <cr> to a <cr><lf> sequence.
151
  if (ch == '\r')
152
    PutChar ('\n');
153
}
154
155
156
//! \brief Main loop 
157
158
int main ()
159
{
160
  // Turn off any interrupts, just in case.
161
  cli ();
162
163
  // ----------------------------------------------------------------------------------------------
164
165
  // Configure the oscillator from internal 2MHz clock to external 8MHz crystal and internal
166
  // PLL quadruplication.
167
168
  // Switch to external crystal (8 MHz) and wait for it to become stable.
169
  OSC.XOSCCTRL = OSC_FRQRANGE_2TO9_gc | OSC_XOSCSEL_XTAL_16KCLK_gc;
170
171
  OSC.CTRL = OSC_XOSCEN_bm | OSC_RC2MEN_bm;
172
  while ((OSC.STATUS & OSC_XOSCRDY_bm) != OSC_XOSCRDY_bm);
173
174
  // Set all the prescalers after the PLL to 1
175
  CCPWrite (&CLK.PSCTRL, CLK_PSADIV_1_gc | CLK_PSBCDIV_1_1_gc);
176
177
  // Activate the PLL with a multiplier of four to generate 32 MHz out of 8 MHz.
178
  OSC.PLLCTRL  = 4 << OSC_PLLFAC_gp | OSC_PLLSRC_XOSC_gc;
179
180
  OSC.CTRL = OSC_XOSCEN_bm | OSC_RC2MEN_bm | OSC_PLLEN_bm;
181
  while ((OSC.STATUS & OSC_PLLRDY_bm) != OSC_PLLRDY_bm);
182
183
  // Switch from internal 2 MHz to 32 MHz PLL output.
184
  CCPWrite (&CLK.CTRL, CLK_SCLKSEL_PLL_gc);
185
186
  // ----------------------------------------------------------------------------------------------
187
188
  // Configure the USART C1 to 57600 baud 8N1, no handshake. Only polling will we used to
189
  // avoid any interrupts in the boot loader firmware.
190
191
  // Values calculated from baud rate and CPU Clock:
192
  // BSEL       1.079   (Select a BSEL Value from 0 to 4095)
193
  // BSCALE     -5      (Select a BSCALE Value from -7 to 7)
194
  // CLK2X      0       (Select 2x speed mode)
195
  // Error%     0,01%   (Error from selected baud rate)
196
  //
197
  // Values calculated from BSEL, BSCALE and CLK2X:
198
  // Baud rate  57.606  bits per second
199
  // Error%     0,01%   error from selected baud rate
200
201
#define BSEL 1079
202
#define BSCALE 11      // -5 in 4-bit two's complement writing
203
204
  // Enable output functionality for the TXD pin.
205
  USARTport.DIRSET = USARTtxd;
206
207
  // Set baud rate generation to 57600 baud.
208
  USARTxx.BAUDCTRLA = (tUINT8) BSEL;
209
  USARTxx.BAUDCTRLB = (BSCALE << USART_BSCALE0_bp) | (BSEL >> 8);
210
  // Set USART to asynchronous mode and format to 8N1.
211
  USARTxx.CTRLC = USART_CHSIZE_8BIT_gc | USART_PMODE_DISABLED_gc | USART_CMODE_ASYNCHRONOUS_gc;
212
  // Enable Rx and Tx, no clock doubling, no multiprocessor communication at all.
213
  USARTxx.CTRLB = USART_RXEN_bm | USART_TXEN_bm;
214
  // Disable all interrupts.
215
  USARTxx.CTRLA = 0;
216
217
#undef BSEL
218
#undef BSCALE
219
220
  // ----------------------------------------------------------------------------------------------
221
222
  PutChar ('H');
223
  PutChar ('e');
224
  PutChar ('l');
225
  PutChar ('l');
226
  PutChar ('o');
227
  PutChar ('!');
228
  PutChar ('\r');
229
230
  while (1)
231
  {
232
    PutChar (GetChar ());
233
  }
234
}

Das geht!

Gruß
Carsten

PS: Nicht vergessen: TxD & RxD über Kreuz anschließen! :-)

von Florian M. (Firma: FZMB GmbH) (florianm)


Lesenswert?

Danke für die Hilfe,

ich werde mir so einen Quarz besorgen,und dann mal testen...

Gruß

Florian

von Florian M. (Firma: FZMB GmbH) (florianm)


Lesenswert?

Hallo Carsten,

Dein Code mit dem 8Mhz Quarz läuft einwandfrei... Danke für die Hilfe!

Ich hatte vorher noch eine andere Variante ohne externen Quarz getestet 
und die lief auch, allerdings verstehe ich noch nicht so genau warum...
Ich habe ein Beispiel von folgendem link 
(http://www.basteln-mit-avr.de/atxmega128a3.html#anfaenger) verwendet 
und für den atxmega 256a3b compiliert. Damit funktionierte die serielle 
Übertragung auch auf Anhieb.

Dort wird der USART folgendermaßen initialisiert:
1
void uartInit(void)
2
{
3
  PORTF.DIRSET = PIN3_bm;  // Pin33 von PORTE3 (TXD0) ist Ausgang                          
4
  PORTF.DIRCLR = PIN2_bm;  // Pin32 von PORTE2 (RXD0) ist Eingang                          
5
6
    // Init USART 115200bps -> (F_CPU 16000000 = 0xD7/0x93)     
7
    // Init USART 115200bps -> (F_CPU 32000000 = 0x17/A4)
8
  // Init USART 115200bps -> (F_CPU 8000000  = 0xAC/91)
9
  
10
  // Init USART 9600 bps  -> (F_CPU 32000000 = 0x7B/0xD6)
11
  // Init USART 9600 bps  -> (F_CPU 16000000 = 0xE5/0xBC)
12
13
14
    USARTF0.BAUDCTRLA = 0x17;   // Init USART 115200bps F_CPU 32Mhz 
15
    USARTF0.BAUDCTRLB = 0xA4;   
16
    USARTF0.CTRLA = 0x10;       // RX is low level interrupt   
17
    USARTF0.CTRLC = 0x03;       // Async, No Parity, 1 stop bit, 8 data bits
18
    USARTF0.CTRLB = 0x18;       // Enable RX and TX // kein CLK2X  !!!!!
19
20
  USARTF0.CTRLA =  USART_RXCINTLVL0_bm | USART_DREINTLVL0_bm;
21
  
22
}

Die System Clock wird dort folgendermaßen eingestellt:
1
void system_clocks_init(void)
2
{
3
  unsigned char n,s;
4
  s=SREG;
5
  cli();
6
  // Internal 32 MHz RC oscillator initialization
7
  // Enable the internal 32 MHz RC oscillator
8
  OSC.CTRL|=OSC_RC32MEN_bm;
9
  n=(CLK.PSCTRL & (~(CLK_PSADIV_gm | CLK_PSBCDIV1_bm | CLK_PSBCDIV0_bm))) |
10
  CLK_PSADIV_1_gc | CLK_PSBCDIV_1_1_gc;
11
  CCP=CCP_IOREG_gc;
12
  CLK.PSCTRL=n;
13
  // Disable the autocalibration of the internal 32 MHz RC oscillator
14
  DFLLRC32M.CTRL&= ~DFLL_ENABLE_bm;
15
  // Wait for the internal 32 MHz RC oscillator to stabilize
16
  while ((OSC.STATUS & OSC_RC32MRDY_bm)==0);
17
  // Select the system clock source: 32 MHz Internal RC Osc.
18
  n=(CLK.CTRL & (~CLK_SCLKSEL_gm)) | CLK_SCLKSEL_RC32M_gc;
19
  CCP=CCP_IOREG_gc;
20
  CLK.CTRL=n;
21
  // Disable the unused oscillators: 2 MHz, internal 32 kHz, external clock/crystal oscillator, PLL
22
  OSC.CTRL&= ~(OSC_RC2MEN_bm | OSC_RC32KEN_bm | OSC_XOSCEN_bm | OSC_PLLEN_bm);
23
  // Restore interrupts enabled/disabled state
24
  SREG=s;
25
}

Jetz sind mir die Werte für die Register BAUDCTRLA und B unklar...
BAUDCTRLA = 0x17 --> 00010111
BAUDCTRLB = 0xA4 --> 10100100
Wenn ich da Datenblatt richtig verstehe müsste dann BSEL = 010000010111 
--> 1047 sein und BSCALE = 10...

Diese Werte stimmen nicht mit den Werten überein, die von diversen 
Baudratenrechnern für 115200 Baud ausgegeben werden..warscheinlich habe 
ich da etwas übersehen...

Ich werde aber die Variante mit dem 8Mhz Quarz benutzen, das erscheint 
mir irgendwie robuster!

Gruß

Florian

von ich (Gast)


Lesenswert?

Lad dir die Aplication Note für den USART runter. Dort ist eine 
Exceltabelle dabei die dir alle möglichen Einstellung für eine Baudrate 
aufzeigt. Sehr hilfreich.

von jonas biensack (Gast)


Lesenswert?

Florian Meuche schrieb:
> USARTF0.CTRLA = 0x10;       // RX is low level interrupt
>     USARTF0.CTRLC = 0x03;       // Async, No Parity, 1 stop bit, 8 data bits
>     USARTF0.CTRLB = 0x18;       // Enable RX and TX // kein CLK2X  !!!!!

hier überschreibst du dass oben!
Das kann nicht gehen...

>   USARTF0.CTRLA =  USART_RXCINTLVL0_bm | USART_DREINTLVL0_bm;

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.