AVR ATMega128 SPI-konstigheter

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
karlstedt
EF Sponsor
Inlägg: 966
Blev medlem: 14 oktober 2003, 16:55:23
Ort: Lund
Kontakt:

AVR ATMega128 SPI-konstigheter

Inlägg av karlstedt »

Jag har stött på ett underligt fenomen när jag försöker använda SPI-bussen i mega128 (ATMEGA128-16AI 0314). Problemet uppstår när jag försöker initiera AVRen som master med SPI-klockan delad med 128 gentemot systemklockan. Då hamnar AVRen i interruptvektorn direkt och överföringen fungerar ej!? Delar jag klockan med 64 eller 16 så funkar det klockrent som förväntat. Nån som har stött på något liknande? Jag har letat igenom hela internet från början till slut, tittat i errata från Atmel osv. Jag inser ju att detta inte kan vara en hårdvarubugg efter alla år mega128 har funnits. Vad gör jag för fel???

Här är min lilla testapplikation:

Kod: Markera allt

#define uint16 						uint16_t
#define uint8 						uint8_t
#define SET_LED() 					PORTE|=(1<<PE6)
#define CLR_LED() 					PORTE&=~(1<<PE6)
#define TGL_LED() 					PORTE^=(1<<PE6)


#define CS_ENABLE() 					PORTE|=(1<<PE0)
#define CS_DISABLE() 					PORTE&=~(1<<PE0)

#define DDR_SPI 					(DDRB)
#define DD_MOSI 					(PB2)
#define DD_SCK						(PB1)
#define DD_CS						(PE0)
#define AVR_SS					    	(PB0)


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdbool.h>

ISR(SPI_STC_vect)
{
  TGL_LED();
}

void delay_ms(uint16 delay);
void SPI_MasterInit(void);
void SPI_MasterTransmit(uint8 cData);
bool MAX5482_Send(uint16 WiperValue);
int main(void)
{
  DDRE = 0xFF;
  SREG |= (1<<SREG_I);

  SPI_MasterInit();

  while(1)
  {
  	MAX5482_Send(0);
	delay_ms(3000);
  	MAX5482_Send(125);
	delay_ms(3000);
  	MAX5482_Send(250);
	delay_ms(3000);
  	MAX5482_Send(512);
	delay_ms(3000);
  	MAX5482_Send(1023);

  	while(1)
	  ;
  }
  return 0;
}

void delay_ms(uint16 delay)
{
  while(delay--)
  _delay_ms(1);
}

void SPI_MasterInit(void)
{
  // Set MOSI, SCK and SS output, all others input 
  DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK) | (1<<AVR_SS);
  PORTB |= (1<<AVR_SS);

  // Enable SPI, Master, set clock rate fck/128 --- Detta fungerar inte!!!
 SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPIE) | (1<<SPR1) | (1<<SPR0) | (1<<CPOL);
  
  // Enable SPI, Master, set clock rate fck/64 --- Detta fungerar 
  //SPCR = (1<<MSTR) | (1<<SPE) | (1<<SPIE) | (1<<SPR1) | (1<<CPOL);
  
}



void SPI_MasterTransmit(uint8 cData)
{
  cData = ~cData;
  // Start transmission
  SPDR = cData;
  // Wait for transmission complete
  while(!(SPSR & (1<<SPIF)))
  ;
}

bool MAX5482_Send(uint16 WiperValue)
{
	bool RetVal;
	RetVal = true;

	if(WiperValue>1023)
	  RetVal = false; 

	CS_ENABLE();
	_delay_us(5);
	SPI_MasterTransmit(0x00);
	SPI_MasterTransmit((WiperValue>>2));
	SPI_MasterTransmit((WiperValue<<8));
	_delay_us(5);
	CS_DISABLE();
	_delay_ms(12);
	
	return RetVal;
}
Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

Hej, ditt fel är att du både har interupt och busy wait loop...

Vad som händer när du får ett interupt är att "huvud programmet" av bryts och interupt rutinen körs, vilket resulterar i flagan blir "clearad".
Detta i sin tur innebär att du kan bli fast i "busy wait loop" efter som flaggan blir "clearad" när den ska testas.... viket leder till en evighets loop.

Att det fungerar vid 64 och 16 är ren "tur", en instruktion till så hade 128 fungerat men inte 64 och 16....

Hoppas gav svar på några frågor ^^
Skriv svar