AVR USART-problem

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
PaNiC
Inlägg: 2610
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

AVR USART-problem

Inlägg av PaNiC »

Så har vi kommit till en av de situationer där allting fungerar i simulator (Proteus/ISIS) men inte i verkligheten.
I verkligheten finns alla symptom för baudrateproblem, men koll i oscilloskop och hundra gånger-koll av alla klockor och UBRR kan utesluta detta.
Det gäller Mega88 med följande kod som känns relevant;

Kod: Markera allt

void setup(void)
{

	DDRD =  0b01101010;
	PORTD = 0b10010100;
	DDRC =  0b00111011;
	DDRB =  0b00000111;
	TCCR0A = 0b10100011; /* fast PWM, set at TOP, clear on match */
	TCCR0B = 0b00000001; /* prescaler at 0 */
	TCCR1A = 0b10100001; /* fast PWM, set at TOP, cleat on match */
	TCCR1B = 0b00001100; /* prescaler at 256, TCCR2A = 0b00100011; 
				fast PWM, set at TOP, clear on match, 
				not OC2A */
	TCCR2B = 0b00000001; /* Prescaler at 1024 */
	TIMSK2 = 0b00000001; /* tim2 ovf interrupt enable, 14Hz. */
	UCSR0A = 0b00000000;
	UCSR0B = 0b00011000; /* Receiver transmitter enabled, RXC interrupt disabled */
	UCSR0C = 0b00000110; /* 8 bits */

	UBRR0L = 23;	     /* 19k2 at 3686400Hz */
	ADMUX = 0b01000000;  /* AVCC as ref, ADC channel 0 */
	ADCSRA = 0b10000111; /* ADC enabled, CLK/128 prescaler */
	ADCSRB = 0b00000000; /* Auto trigger is off */
	DIDR0 = 0b00000100;  /* Disables digital input of ADC2 */
	EICRA = 0b00000011;  /* Rising edge of INT0 generates interrupt */
	EIMSK = 0b00000001;	 /* Enables INT0 */
}

int main(void)
{
	PORTB |= WMP;
	UDR0 = 0x9a;
	setup();
	
	sei();
	
	while(1) {
	if(UCSR0A & 0b10000000){
		PORTB |= CST;
		usart_recv();
	}
	}
}	


Klockan är 73728800Hz och UARTens hastighet verifierad med oscilloskop är 19,2kbaud.
Det finns inga tecken på att AVRens UART registrerar någon mottagen data alls, och sänd data blir jibberish, dock utan att terminalprogrammet larmar för felaktig baudrate. Vidare körs main() over and over trots att programmet borde fastna i while(1) i väntan på att antingen if(UCSR0A & 0b10000000) eller timer-interrupt ska ske.
Samma fel uppträder på två Mega88 på helt olika kort.
Förslag?
Senast redigerad av PaNiC 3 augusti 2010, 16:50:32, redigerad totalt 1 gång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: AVR USART-problem

Inlägg av sodjan »

Hur ser jibberish ut ?
Användarvisningsbild
PaNiC
Inlägg: 2610
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Re: AVR USART-problem

Inlägg av PaNiC »

sodjan, all annan data än vad det borde vara. Men som exempel blir 0xAA 0xD5 och 0xBA blir 0xE6.
sneaky
Inlägg: 1621
Blev medlem: 22 juni 2009, 18:38:42

Re: AVR USART-problem

Inlägg av sneaky »

Kan inget om AVR men det känns ju märkligt att den "loopar" main() istället för att gå vidare så att säga. Det är inte så att det är något brown out-skydd som löser ut eller motsvarande?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: AVR USART-problem

Inlägg av sodjan »

> Men som exempel blir 0xAA 0xD5 och 0xBA blir 0xE6.

Blir 0xAA konsekvent 0xD5 och 0xBA konsekvent 0xE6 ?
Och vilket av tecknen ser du på oscilloskopet ?
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Re: AVR USART-problem

Inlägg av thepirateboy »

Hur är "fusarna" inställda?
Användarvisningsbild
Swech
EF Sponsor
Inlägg: 4750
Blev medlem: 6 november 2006, 21:43:35
Ort: Munkedal, Sverige (Sweden)
Kontakt:

Re: AVR USART-problem

Inlägg av Swech »

Kod: Markera allt

UCSR0A = 0b00000000;
är fel eftersom du kör med 23 som baudrate
skall vara

Kod: Markera allt

UCSR0A = 0b00000010;
Men ett tips är att deifiera upp dina flaggbitar också så blir det mycet enklare att läsa.

Kod: Markera allt

.equ    u2x0 = 1 << 1
UCSR0A = u2x0   
inget fuse problem alltså

Swech
Användarvisningsbild
PaNiC
Inlägg: 2610
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Re: AVR USART-problem

Inlägg av PaNiC »

Swech, vad skulle det hjälpa att sätta U2X? Då får jag ju bara 38,4kbaud istället?

thepirateboy skrev:Hur är "fusarna" inställda?
Endast EESAVE, ingen BOD, extern full swing-kristall.
sodjan skrev:> Men som exempel blir 0xAA 0xD5 och 0xBA blir 0xE6.

Blir 0xAA konsekvent 0xD5 och 0xBA konsekvent 0xE6 ?
Och vilket av tecknen ser du på oscilloskopet ?
0xD5 är konsekvent, 0xE6 är blandat med 0xF9. Jag får återkomma med vad som hamnar på skopet, men tror inte att datorn tar emot fel.

sneaky skrev:Kan inget om AVR men det känns ju märkligt att den "loopar" main() istället för att gå vidare så att säga. Det är inte så att det är något brown out-skydd som löser ut eller motsvarande?
Det tänkte jag också, men vid inget tillfälle sjunker matningen under normalt, men jag provade iaf att stänga av BOD utan framgång.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: AVR USART-problem

Inlägg av sodjan »

Du säger ingenting om hur det hela är kopplat.
Användarvisningsbild
mri
Inlägg: 1165
Blev medlem: 15 mars 2007, 13:20:50
Ort: Jakobstad, Finland
Kontakt:

Re: AVR USART-problem

Inlägg av mri »

"Vidare körs main() over and over trots att programmet borde fastna i while(1) i väntan på att antingen if(UCSR0A & 0b10000000) eller timer-interrupt ska ske."

Glöm allt vad UART heter och fixa detta först. Du måste ju få själva processorn att exekvera stabilt innan du kan börja lägga till fuktioner för seriekommunikation och felsöka den biten.
Användarvisningsbild
PaNiC
Inlägg: 2610
Blev medlem: 15 augusti 2003, 22:16:15
Ort: Skånelandet

Re: AVR USART-problem

Inlägg av PaNiC »

sodjan skrev:Du säger ingenting om hur det hela är kopplat.
Det finns inte så mycket att säga. Enklast möjliga, µC, max3232 på ena kortet och 202 på andra, till serieport.


mri: Jovisst, det kan jag hålla med om, och jag säger inget om att problemen är orelaterade. Förslag på vad jag bör kolla?
Edit: mri, stängde av timer2 OVF-interruptet vilket fick rätt på detta. Får felsöka det senare.

Nu återigen, sänder ett 0xAA från AVRen och får 0xD5 i datorn.

sodjan: 11010101, dvs D5 sänds från µC när jag tittar i skopet.

Edit2:
Nu blir jag bestört. Sedan jag stängde av interruptet har visserligen inte den första byten jag sänder blivit rätt, men efterföljande trafik är ok. Detta till trots har det hela tiden fungerat i simulatorn.

Det är kanske på sin plats att posta all kod:

Kod: Markera allt

#include "avr/io.h"
#include "avr/interrupt.h"
#include "stdlib.h"
#include "stdio.h"
#include "avr/eeprom.h"
#include "util/delay.h"
#include "math.h"


#define tempchan 2
#define poschan 6
#define negchan 7
#define CMP 0b00100000
#define CST 0b00001000
#define WMP 0b00010000

unsigned char k_type;
unsigned char sinpos = 0;
signed int EHAcomp;	 /*How much EHA is compensated */
unsigned int EHAinpos;	 /* EHA input, positive */
unsigned int EHAinneg;	 /* EHA input, negative */
signed int EHAinact;	 /* EHA actual input, diff between pos/neg */
unsigned char EHAshould; /* What value EHAact should have */
signed int EHAout;
unsigned char sercount = 14; //
unsigned char out_a;
unsigned char out_b;

/*
ADC6 - EHA in 1
ADC7 - EHA in 2
ADC2 - LM335 in
PC0.1 - EHA ground transistors
INT0 - Sense pwr off
OC2B - Q3(X3-2)
PD4 - OK2 (remember to pull up internally)
OC0B - ana out, X3-4
OC0A - ana out, X3-3
PD7 - KE3-jumper (remember to pull up internally)
OC1A - Q1(X3-6)
OC1B - Q2(X3-5)
*/

/* 
 * sends string on uart 
 */
void uart_sendstring(char *str) 
{
	int i;
	for(i = 0; str[i] != 0; i++) {
		while(!(UCSR0A & _BV(UDRE0)));
		UDR0 = str[i];
	}
		while(!(UCSR0A & _BV(UDRE0)));
		UDR0 = 4;
}


unsigned int adcread(unsigned char chan)
{
	unsigned char t;
	unsigned int result;
	/* selects channel, as well as voltage reference */
	ADMUX = (0b01000000 | chan); 
	/* Start ADC conversion */
	ADCSRA |= 0b01000000; 
	/* waits for conversion to be done */
	while(ADCSRA&0b01000000); 
	result = (ADCH<<8 | ADCL);
	/* workaround for reading ADCH last */
	t = ADCH; 
	return result;
}


unsigned int gettemp(void)
{
	unsigned int t;
	/* unsigned int i; */
	t = adcread(tempchan);
	/* workaround for reading ADCH last */
	/* i = ADCH; */
	/* some shit to convert the read value to temperature */
	t *= 25; 
	t >>= 1;
	t *= 5;
	t >>= 7;
	return t;
}

unsigned char getcoldduty(void) {
	unsigned char d;
	unsigned int t = gettemp();
	/* Ninja magic for a reasonable relation 
	   between temp and CS valve duty% */
	signed int c = (5*(313-t));

	if(c < 1) {
		d = 0;
	}
	if(c > 254) {
		d = 255;
	}
	if((c < 255) && (c > 0)) {
		d = c;
	}
	return d;
}    
void setup(void)
{

	DDRD =  0b01101010;
	PORTD = 0b10010100;
	DDRC =  0b00111011;
	DDRB =  0b00000111;
	TCCR0A = 0b10100011; /* fast PWM, set at TOP, clear on match */
	TCCR0B = 0b00000001; /* prescaler at 0 */
	TCCR1A = 0b10100001; /* fast PWM, set at TOP, cleat on match */
	TCCR1B = 0b00001100; /* prescaler at 256, TCCR2A = 0b00100011; 
				fast PWM, set at TOP, clear on match, 
				not OC2A */
	TCCR2B = 0b00000001; /* Prescaler at 1024 */
	//TIMSK2 = 0b00000001; /* tim2 ovf interrupt enable, 14Hz. */
	UCSR0A = 0b00000000;
	UCSR0B = 0b00011000; /* Receiver transmitter enabled, RXC interrupt disabled */
	UCSR0C = 0b00000110; /* 8 bits */

	UBRR0L = 23;	     /* 19k2 at 3686400Hz */
	ADMUX = 0b01000000;  /* AVCC as ref, ADC channel 0 */
	ADCSRA = 0b10000111; /* ADC enabled, CLK/128 prescaler */
	ADCSRB = 0b00000000; /* Auto trigger is off */
	DIDR0 = 0b00000100;  /* Disables digital input of ADC2 */
	EICRA = 0b00000011;  /* Rising edge of INT0 generates interrupt */
	EIMSK = 0b00000001;	 /* Enables INT0 */
	
	/* determines if KE3 jumper is in place */
	if(PIND & 0b10000000) { 
		k_type = 3;
	} else {
		k_type = 0;
	}		
	

	//EHAcomp = eeprom_read_word((uint16_t*)12);
	sei();
}

/* 
 * calculates the actual compensation for EHA value and outputs to DA 
 * converter. OCR0A is positive output, OCR0B is negative output
 */


void regulate_lambda(void) 	{

	unsigned char t;
	/* these two lines output cold start duty% on CS valve. */
	OCR2B = getcoldduty();
	
	/* this determines the supposed value of EHA signal, 
	   depending on KE or KE3. */
	if(PIND & 0b10000000)	
		EHAshould = 41;
	else
		EHAshould = 0;

	
	EHAinpos = adcread(poschan);
	EHAinneg = adcread(negchan);
	EHAinact = (EHAinpos - EHAinneg);


	if(!OCR2B){ /*Only regulate if no cold start is taking place */
		/* 12 gives a tolerance of about 3mA before an action is taken. */
		if(EHAinact > (EHAshould + 12) && (EHAcomp < 127)) { 
			EHAcomp++;
		}
		/* this is where the actual regulation is */
		if(EHAinact < (EHAshould - 12) && (EHAcomp > -127)) {
			EHAcomp--;
		}
	}
	
	/* if output is within range of 8b, go ahead. */
	if((EHAcomp + EHAinact) > -255 && ((EHAcomp + EHAinact)) < 255) {
		EHAout = (EHAcomp + EHAinact);
	}
	/* if output is above range of 8b */
	if((EHAcomp + EHAinact) > 255) {
		EHAout = 254;
	}
	/* if output is below range of 8b */
	if((EHAcomp + EHAinact) < -255)	{
		EHAout = -254;
	}
	/* if output is positive and within range */
	if(EHAout > 0 && EHAout < 255) {
		out_a = EHAout;
		out_b = 0;
	}
	/* if output is positive and below range */
	if(EHAout < 0 && EHAout > -255) {
		/* make output positive and output to PWM */
		t = (EHAout - (2*EHAout));
		out_b = t;
		out_a = 0;
	}
		
	/* pos=OC0B, neg=OC0A, controls output transistors */
	if(out_a > out_b) {
		PORTC &= 0b11111101;
		PORTC |= 0b00000001;
		OCR0A = out_a;
		OCR0B = out_b;
	}
	if(out_b > out_a) {
		PORTC &= 0b11111110;
		PORTC |= 0b00000010;
		OCR0A = out_a;
		OCR0B = out_b;
	}
	
	/*
	if((EHAcomp + EHAinact) > 0 && ((EHAcomp + EHAinact) < 255)) {
		OCR0B = 0;
		OCR0A = (EHAcomp + EHAinact);
	}
	if((EHAcomp + EHAinact) < 0 && ((EHAcomp + EHAinact) > -255)) {
		t = (EHAcomp + EHAinact);
		t &= 0b01111111;
		OCR0B = t;
		OCR0A = 0;
	}
	*/



}

ISR(INT0_vect) /* shutdown procedure, EHAcomp must be saved in eeprom */
{
	cli();
	OCR0B = 0;
	OCR0A = 0;
	OCR2B = 0;
	eeprom_write_word((uint16_t*)12,EHAcomp);
	UDR0 = 'k';
	unsigned int d = 0xffff;
	while(PIND&0b00000100);
	while(d) d--;
	setup();
}

void usart_recv()
{
	char str[12];
	char byte;
	PORTB |= 0b00000001;
	byte = UDR0;
	if(byte == 0xf0) UDR0 = 4;
	if(byte == 0xf1){
		sprintf(str, "Comp   %.3d", EHAcomp);
		uart_sendstring(str);
	}
	if(byte == 0xf2){
		sprintf(str, "In act %.3d", EHAinact);
		uart_sendstring(str);
	}
	if(byte == 0xf3){
		sprintf(str, "Temp   %.3d", (gettemp() - 273));
		uart_sendstring(str);
	}
	if(byte == 0xf4){
		sprintf(str, "CSV    %.3d", OCR2B);
		uart_sendstring(str);
	}
	if(byte == 0xf5){
		sprintf(str, "Out act");
		uart_sendstring(str);
	}


}

ISR(TIMER2_OVF_vect)
{
	//cli();
	regulate_lambda();
	PORTB |= 0b00000100;
	//UDR0 = '0';
	sei();
}

int main(void)
{
	PORTB |= WMP;
	UDR0 = 0xaa;
	setup();
	
	sei();
	
	while(1) {
	/*	if(PORTB & 0b00000001) {
			PORTB &= 0b11111110;
		}
		else {
			PORTB |= 0b00000001;
		}*/
	if(UCSR0A & 0b10000000){
		PORTB |= CST;
		usart_recv();
	}
	}
}			
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: AVR USART-problem

Inlägg av sodjan »

> Enklast möjliga, µC, max3232 på ena kortet och 202 på andra, till serieport.

Och allt är *rätt* kopplat ? Det kan ju *vi* omöjligt veta. Att du bara säger
att du använder den och den kretsen säger inte så mycket.

Serieport vardå ? Vad är "202" ?? MAX202 ?
Om du har en riktig RS232 serieport i det du kallar "på andra" så ser jag inte
varför du behöver mer än *en* RS232 omvandare (på AVR sidan).

Som sagt, hafsa inte över det, tala om vad du har för prylar
och hur det är kopplat...

> Det är kanske på sin plats att posta all kod:

Det finns ingen som helst anledning att posta hela den där koden.
Det räcker med den lilla testkod som du bör ha skrivit för att testa
seriekommunikationen och som visar problemet. Allt annat är ointressant
och är bara "i vägen". Ta bort allt som har med ADC, EEPROM, lambda o.s.v
som inte direkt har med USART'en att göra.
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: AVR USART-problem

Inlägg av blueint »

ADC, EEPROM, lambda osv. Kan påverka USART.
Fast det första är förstås att ringa in problemet ordentligt.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: AVR USART-problem

Inlägg av sodjan »

Japp, minska ner koden tills antingen problemet försvinner (eller är
kvar och fixa det) sedan lägg till de andra funktionerna en-och-en
med verifiering mellan varje steg. Finns igentligen inget annat
sätt att felsöka.
Användarvisningsbild
Icecap
Inlägg: 26658
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: AVR USART-problem

Inlägg av Icecap »

Ett tips rörande att första byten inte blir rätt: När du initierar UART'en ska du lägga '1' ut på portpinnen som är UART TX. Jag hade samma (fast på PIC) och sagde en del ord om det men kom på, medelst oscilloskop, att då "stand by" på en UART TX är '1' och porten blev nollat vid reset kom den att så fast på '0' till första byten har gått iväg, sedan kommer nivån rätt.

Så initiera UART'en, sätt portpinnen till '1' och saken är biff.
Skriv svar