LusoRobótica - Robótica em Português
Sistemas específicos => Arduino / AVR => Tópico iniciado por: metRo_ em 10 de Abril de 2011, 20:57
-
Estou a tentar colocar o SPI do atmega328p a funcionar no entanto não está facil, tenho este código, as funções foram retiradas da datasheet.
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include "bit_tools.h"
#define DDR_SPI DDRB
#define DD_SS DDB2
#define DD_MOSI DDB3
#define DD_MISO DDB4
#define DD_SCK DDB5
void SPI_MasterInit(void){
/* Set MOSI and SCK output, all others input */
DDR_SPI = (1<<DD_SS)|(1<<DD_MOSI)|(1<<DD_SCK);
/* Enable SPI, Master, set clock rate fck/16 */
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
}
void SPI_MasterTransmit(char cData){
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)))
;
}
int main(void) {
SPI_MasterInit();
sei();
DDRB |= (1<<PB1);
bit_clear(PORTB,PB1);
bit_set(PORTB,PB2);
while(1){
bit_clear(PORTB,PB1);
bit_set(PORTB,PB1);
bit_clear(PORTB,PB1);
bit_set(PORTB,PB1);
bit_clear(PORTB,PB1);
bit_set(PORTB,PB1);
bit_clear(PORTB,PB1);
SPI_MasterTransmit(0x0F);
_delay_ms(1);
}
return 0;
}
O que parece estar a acontecer é que ele fica parado dentro da função de SPI_MasterTransmit, eu neste momento não tenho nenhum slave, será por isso?! Só queria mesmo configurar e ver os sinais.
Estou a ver os sinais num logic analyser.
EDIT1:
Ás vezes a comunicação é feita mas não o SS não muda.
-
Já estou meio enferrujado, mas não tens de fazer isso manualmente?
-
Será?! :s
-
Axo que sim, senão imagina como era se tivesses vários slaves... já para não dizer que podias ter algum tempo de espera após activar o chip select do slave... embora também pudesse dar para usar os dois modos por isso vê melhor no datasheet que ele é que manda :)
-
Não estive a comparar os códigos com atenção mas eu uso isto:
#define MOSI PB3
#define MISO PB4
#define SCK PB5
#define SS PB2
#define ADDR 0x06 //Address/configuration byte for the spi ADC
#define DUMMY 0x00 //Dummy byte, because in each SPI comm we must send data
#define DATA_MASK 0x0F //Mask used to extract the first 4 bits that arrive in the second byte received
void SPI_init(void){
DDRB |= ((1<<MOSI)|(1<<SCK)|(1<<SS)); //Mosi, sck and ss are outputs
DDRB &= (~(1<<MISO)); //Miso is input
PORTB |= (1<<SS); //Start with SS at 1 (HIGH)
//Enable SPI, Master mode
//MSB first
//CPOL=0
//CPHA=0
//SPI mode 0
//sck = F_CPU/16 = 1Mhz
//SPSR = (1<<SPI2X); //SPI clock x2
SPCR = ((1<<SPE)|(1<<MSTR)|(1<SPR0));
}
uint8_t SPI_Write(uint8_t data){
SPDR = data; //Start data transfer
while(!(SPSR & (1<<SPIF))); //Wait for the end of the transmission
return SPDR; //Return the received data
}
Isto é para falar com um ADC 12 bits da Microchip de 8 canais, um MCPxx08 qualquer, o SPI_Write escreve e lê, pois o SPI envia e recebe os dados de uma só vez.
-
Boas,
Quando a SPI está a funcionar em modo Master o pin SS pode estar em duas situações:
- Se SS é configurado como output então este pin pode ser usado como um pin IO normal e o seu estado não altera a funcionalidade da interface SPI MASTER.
- Se SS for configurado como input então deve ser mentido com um nível high, e for levado a low a interface SPI interpreta isso como um pedido de um outro Master e muda para o modo Slave.
Resumindo, em modo Master SS deve ser configurado como output e pode (ou não) ser usado para seleccionar um Slave devendo para ir ser levado a high programaticamente
Abraços,
PA
-
Estou a usar o SPI num projecto e dessa mesma forma, talvez o problema seja mesmo por não haver um slave...
-
@senso Tu no main não mexes mais no SS!?
Quando a SPI está a funcionar em modo Master o pin SS pode estar em duas situações:
- Se SS é configurado como output então este pin pode ser usado como um pin IO normal e o seu estado não altera a funcionalidade da interface SPI MASTER.
- Se SS for configurado como input então deve ser mentido com um nível high, e for levado a low a interface SPI interpreta isso como um pedido de um outro Master e muda para o modo Slave.
Resumindo, em modo Master SS deve ser configurado como output e pode (ou não) ser usado para seleccionar um Slave devendo para ir ser levado a high programaticamente
Abraços,
PA
Só para ter a certeza se o meu atmega está a funcionar como master tenho que ser eu a comandar o SS!?
-
No main não, na função que lê o ADC sim, esqueci-me de meter essa aqui:
uint16_t Read_ADC(uint8_t channel){
uint8_t upper_addr, lower_addr, upper_data, lower_data;
if(channel > 3){
upper_addr = ADDR | 0x01; }
else{
upper_addr = ADDR; }
lower_addr = channel<<6;
PORTB &= (~(1<<SS)); //Put SS at 0 (LOW), to start the data transfer
SPI_Write(upper_addr);
upper_data = SPI_Write(lower_addr);
lower_data = SPI_Write(DUMMY);
upper_data &= DATA_MASK;
PORTB |= (1<<SS); //Puts SS at 1 (HIGH), because we already stoped all the data transfer
return ((upper_data<<8)|lower_data);
}
-
Parece que faltava mexer no ss para isto funcionar :)
Agora o meu problema é converter os sinais de 5v para 3.3v mas acho que ja há aqui um tópico sobre isso, vou procurar, para ja o que noto é que com divisor de tensão, a onda de clock não é tão boa!
EDIT1:
Independentemente do valor que colocar em SPR a velocidade do clock é a mesma :s
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 16000000UL
#include <util/delay.h>
#include "bit_tools.h"
#define MOSI PB3
#define MISO PB4
#define SCK PB5
#define SS PB2
void SPI_init(void){
DDRB |= ((1<<MOSI)|(1<<SCK)|(1<<SS)); //Mosi, sck and ss are outputs
DDRB &= (~(1<<MISO)); //Miso is input
PORTB |= (1<<SS); //Start with SS at 1 (HIGH)
//MSTR: Enable SPI, Master mode
//SPIE: SPI Interrupt Enabl
//(1<SPR1)|(1<SPR0) : FOSC/128
SPCR = ((1<<SPE)|(1<<MSTR)|(1<SPR1)|(1<SPR0));
}
uint8_t SPI_Write(uint8_t data){
SPDR = data; //Start data transfer
while(!(SPSR & (1<<SPIF))); //Wait for the end of the transmission
return SPDR; //Return the received data
}
int main(void) {
SPI_init();
sei();
while(1){
PORTB &= (~(1<<SS)); //Put SS at 0 (LOW), to start the data transfer
SPI_Write(0x01);
SPI_Write(0x41);
SPI_Write(0x05);
SPI_Write(0xff);
PORTB |= (1<<SS); //Puts SS at 1 (HIGH), because we already stoped all the data transfer
_delay_ms(100);
}
return 0;
}
EDIT2
Tem aqui as imagens:
Sem divisor:
(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fimg197.imageshack.us%2Fimg197%2F5892%2Fspiram.png&hash=528a863387369568e7fb53b83c4c23c743edc899)
Com divisor:
(https://lusorobotica.com/proxy.php?request=http%3A%2F%2Fimg15.imageshack.us%2Fimg15%2F3097%2Fspiram1.png&hash=399b1d7e1cf31cc0ace189acf91eaec0d37ac85d)
-
Boas,
metRo_, que LigicSniffer é esse que estás a usar ?
Abraços,
PA
-
Boas,
metRo_, que LigicSniffer é esse que estás a usar ?
Abraços,
PA
Olá, é o Open Logic Sniffer: http://dangerousprototypes.com/open-logic-sniffer/ (http://dangerousprototypes.com/open-logic-sniffer/)