Страница 1 из 1

Atmega8515 + Spi

Добавлено: Чт окт 30, 2014 17:00:40
shilvlad
Доброго времени суток, друзья.

Всю голову себе сломал об следующую проблему.

Прикручиваю atmega8515 через SPI к W5100. Столкнулся с проблемами в самом начале - в процессе обучения микроконтроллера инициализировать SPI и передать байт.

Делаю инициализацию так:

Код: Выделить всё

void SPI_Init(void)
{
        DDRB |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
        PORTB |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(1<<SPI_MISO);
        SPCR = 0b01110000;
        SPSR = 0b00000000;
}


Передачу байта так:

Код: Выделить всё

void SPI_WriteByte(uint8_t data)
{
        PORTB &= ~(1<<SPI_SS);
        SPDR = data;

        while(!(SPSR & (1<<SPIF)));
        PORTB |= (1<<SPI_SS);
}


В результате стандартной процедуры записи команд в W5100 (к слову, с ардуиной работает) он работать не начал. После долгих мучений появилось подозрение, что я не так что-то с SPI делаю (я, в целом, раньше обходился UART'ом).

Для проверки подозрений накидали для ардуины скетч, который все что получает по SPI выплевывает в ардуиновский Serial. Прицепили мой МК к ардуине - выплевывает в Serial какую-то лажу. Тут я вообще перестал понимать что происходит.

В связи с чем, помогите. Может я какую-то детскую ошибку совершаю. Поглядите, правильно ли я инициализирую SPI и посылаю байт.

Заранее благодарю.

Re: Atmega8515 + Spi

Добавлено: Чт окт 30, 2014 18:30:46
COKPOWEHEU
А Протеус что говорит?

Re: Atmega8515 + Spi

Добавлено: Чт окт 30, 2014 21:41:20
Halex
COKPOWEHEU писал(а):А Протеус ...?
А что в Протеусе есть модель W5100? Что-то за почти десятилетний срок пользования не наблюдал... А со SPI дебаггером выплюнет то, что "доктор прописал".
2 shilvlad А Вы до конца уверены, что бит DORD в SPCR должен стоять??? Вроде как, судя по шиту на W5100, первым едет MSB. МоГет быть здесь "собака порылась"?
Изображение

Re: Atmega8515 + Spi

Добавлено: Чт окт 30, 2014 22:50:21
Ser60
Halex прав. Но помимо этого, зачем Вы дергаете каждый раз CS при передаче байта? Следует эту линию опустить перед передачей первого байта из группы байтов команды и поднять только после передачи всей группы, см. стр. 2 в ДШ. Подробнее см. в статье ниже. Она, правда, для W5200, но с W5100 аналогично.
http://radiokot.ru/circuit/digital/measure/114/

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 00:28:13
shilvlad
Протеусовский SPI Debugger говорит что я что-то не так делаю (см картинку DORD1.jpg) (При этом DORD = 1)


При DORD=0 картинка DORD2.jpg

Код: Выделить всё

void SPI_Init(void){
	DDRB |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
	PORTB |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(1<<SPI_MISO);
 	SPCR = 0b01110000;
	SPSR = 0b00000000;


}

void SPI_WriteByte(uint8_t data){
	PORTB &= ~(1<<SPI_SS);
	SPDR = data;

	while(!(SPSR & (1<<SPIF)));
	PORTB |= (1<<SPI_SS);
}

int main (void){
	SPI_Init();
        while(1){
		_delay_ms(500);
		SPI_WriteByte(0x48);
		_delay_ms(50);
		SPI_WriteByte(0x49);
		_delay_ms(50);
		SPI_WriteByte(0x49);
		_delay_ms(50);
		SPI_WriteByte(0x48);
		_delay_ms(50);
		SPI_WriteByte(0x21);
		_delay_ms(50);

	}
}
За DORD - спасибо. Завтра еще раз попробую.

2 Ser60
Задача с W5100 свелась у меня к проверке того, что передается по SPI. Как мне правильно подсказали, при DORD=0 SPI debugger кажет более кошерный результат, но Ардуинка подключенная SLAVE'ом к моему агрегату плюется в Serial какой-то лажей. Причем двубайтовой (двубайтовость меня заставляет в себе сомневаться сильнее всего).

Завтра на свежую голову еще попрыгаю вокруг SPI и помурыжу Вас еще :)
DORD2.JPG
(91.97 КБ) 554 скачивания
DORD1.JPG
(92.61 КБ) 508 скачиваний

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 10:08:10
shilvlad
Друзья, с учетом Ваших замечаний написана функция записи:
Что бы было понятно где затуп происходит добавил везде вывод номера выполненной команды.
Виснет на строке после "WR - 4".

Надеюсь на Вашу помощь...

Код: Выделить всё

void W5100_Write(uint16_t addr,uint8_t data){
	// Activate the CS pin
	SPI_PORTX &= ~(1<<SPI_SS);
	USART_PrintStr("WR - 1");
	
	// Start Wiznet W5100 Write OpCode transmission
	SPDR = WIZNET_WRITE_OPCODE;
	USART_PrintStr("WR - 2");
	
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	USART_PrintStr("WR - 3");
	
	// Start Wiznet W5100 Address High Bytes transmission
	SPDR = (addr & 0xFF00) >> 8;
	USART_PrintStr("WR - 4");
	
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	USART_PrintStr("WR - 5");
	
	// Start Wiznet W5100 Address Low Bytes transmission
	SPDR = addr & 0x00FF;
	USART_PrintStr("WR - 6");
	
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	USART_PrintStr("WR - 7");
	
	// Start Data transmission
	SPDR = data;
	USART_PrintStr("WR - 8");

	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	USART_PrintStr("WR - 9");
	
	// CS pin is not active
	SPI_PORTX |= (1<<SPI_SS);
	USART_PrintStr("WR - 10");
}
Забыл добавить. Судя по протеусу записывается все по ГОСТ :)

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 11:27:32
shilvlad
Если вдруг кому-либо будет не лень читать, вот мой, уже до неприличия упрощенный, код:

Код: Выделить всё

#define F_CPU 8000000UL

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

// USART
//////////////////////////////////////////////////////////

void USART_Init( unsigned int baud ){
	UBRRH = (unsigned char)(baud>>8);
	UBRRL = (unsigned char)baud;
	UCSRB = (1<<RXEN)|(1<<TXEN)|(1 << RXCIE );
	UCSRC = (1<<URSEL)|(1<<USBS)|(3<<UCSZ0);
}

void USART_Transmit(unsigned char data){
	while ( !( UCSRA & (1<<UDRE)) );
	UDR = data;
}

void USART_PrintStr(char * str){
	int i =0;
	while(str[i] != 0){
		USART_Transmit(str[i]);
		i++;
	}
	USART_Transmit(10);
	USART_Transmit(13);
}

// SPI
//////////////////////////////////////////////////////////
#define SPI_PORTX PORTB
#define SPI_DDRX DDRB

#define SPI_MOSI 5
#define SPI_MISO 6
#define SPI_SCK 7
#define SPI_SS 0


void SPI_Init(void){
	DDRB |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(0<<SPI_MISO);
	PORTB |= (1<<SPI_MOSI)|(1<<SPI_SCK)|(1<<SPI_SS)|(1<<SPI_MISO);
 	//SPCR = 0b01010000;
	//SPSR = 0b00000000;
	SPCR = (1<<SPE)|(1<<MSTR);
	SPSR |= (1<<SPI2X);
}


// W5100 RW functions
/////////////////////////////////////////////////////////////////
#define WIZNET_WRITE_OPCODE 0xF0
#define WIZNET_READ_OPCODE 0x0F


void W5100_Write(uint16_t addr,uint8_t data){
	// Activate the CS pin
	SPI_PORTX &= ~(1<<SPI_SS);
	// Start Wiznet W5100 Write OpCode transmission
	SPDR = WIZNET_WRITE_OPCODE;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// Start Wiznet W5100 Address High Bytes transmission
	SPDR = (addr & 0xFF00) >> 8;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// Start Wiznet W5100 Address Low Bytes transmission
	SPDR = addr & 0x00FF;	
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// Start Data transmission
	SPDR = data;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// CS pin is not active
	SPI_PORTX |= (1<<SPI_SS);
}

unsigned char W5100_Read(unsigned int addr){
	// Activate the CS pin
	SPI_PORTX &= ~(1<<SPI_SS);
	// Start Wiznet W5100 Read OpCode transmission
	SPDR = WIZNET_READ_OPCODE;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// Start Wiznet W5100 Address High Bytes transmission
	SPDR = (addr & 0xFF00) >> 8;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// Start Wiznet W5100 Address Low Bytes transmission
	SPDR = addr & 0x00FF;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// Send Dummy transmission for reading the data
	SPDR = 0x00;
	// Wait for transmission complete
	while(!(SPSR & (1<<SPIF)));
	// CS pin is not active
	SPI_PORTX |= (1<<SPI_SS);
	return(SPDR);
}


// W5100 Initialization
//////////////////////////////////////////////////////////
#define MR   0x0000   // Mode Register
#define GAR  0x0001   // Gateway Address: 0x0001 to 0x0004
#define SUBR 0x0005   // Subnet mask Address: 0x0005 to 0x0008
#define SAR  0x0009   // Source Hardware Address (MAC): 0x0009 to 0x000E
#define SIPR 0x000F   // Source IP Address: 0x000F to 0x0012
#define RMSR 0x001A   // RX Memory Size Register
#define TMSR 0x001B   // TX Memory Size Register

void W5100_Init(void)
{
	// Ethernet Setup
	unsigned char mac_addr[] = {0x00,0x16,0x36,0xDE,0x58,0xF6};
	unsigned char ip_addr[] = {192,168,2,10};
	unsigned char sub_mask[] = {255,255,255,0};
	unsigned char gtw_addr[] = {192,168,2,1};

	// Setting the Wiznet W5100 Mode Register: 0x0000
	
	W5100_Write(MR,0x80);            // MR = 0b10000000;
	_delay_ms(10);

	// Setting the Wiznet W5100 Gateway Address (GAR): 0x0001 to 0x0004
	USART_PrintStr("Setting GW");
	W5100_Write(GAR + 0,gtw_addr[0]);
	W5100_Write(GAR + 1,gtw_addr[1]);
	W5100_Write(GAR + 2,gtw_addr[2]);
	W5100_Write(GAR + 3,gtw_addr[3]);
	_delay_ms(10);
	USART_PrintStr("Checking GW");
	if(W5100_Read(GAR+0) != gtw_addr[0] && W5100_Read(GAR+1) != gtw_addr[1] && W5100_Read(GAR+2) != gtw_addr[2] && W5100_Read(GAR+3) != gtw_addr[3]) {
		USART_PrintStr("GW - Not set");	
	}
	else USART_PrintStr("GW - Set");	
	
	// Setting the Wiznet W5100 Source Address Register (SAR): 0x0009 to 0x000E
	W5100_Write(SAR + 0,mac_addr[0]);
	W5100_Write(SAR + 1,mac_addr[1]);
	W5100_Write(SAR + 2,mac_addr[2]);
	W5100_Write(SAR + 3,mac_addr[3]);
	W5100_Write(SAR + 4,mac_addr[4]);
	W5100_Write(SAR + 5,mac_addr[5]);
	_delay_ms(1);

	// Setting the Wiznet W5100 Sub Mask Address (SUBR): 0x0005 to 0x0008
	W5100_Write(SUBR + 0,sub_mask[0]);
	W5100_Write(SUBR + 1,sub_mask[1]);
	W5100_Write(SUBR + 2,sub_mask[2]);
	W5100_Write(SUBR + 3,sub_mask[3]);
	_delay_ms(1);

	// Setting the Wiznet W5100 IP Address (SIPR): 0x000F to 0x0012
	W5100_Write(SIPR + 0,ip_addr[0]);
	W5100_Write(SIPR + 1,ip_addr[1]);
	W5100_Write(SIPR + 2,ip_addr[2]);
	W5100_Write(SIPR + 3,ip_addr[3]);
	_delay_ms(1);

	// Setting the Wiznet W5100 RX and TX Memory Size, we use 2KB for Rx/Tx 4 channels
	W5100_Write(0x001A,0x55);
	W5100_Write(0x001B,0x55);

	
}


////////////////////////////////////////////////////////////
int main (void)
{
	
	USART_Init(8);
	SPI_Init();
	
	unsigned char gtw_addr[] = {192,168,2,1};

	W5100_Write(MR,0x80);            // MR = 0b10000000;
	_delay_ms(100);

	W5100_Write(GAR + 0,gtw_addr[0]);
	_delay_ms(100);
	
	if(W5100_Read(GAR+0) != gtw_addr[0]) {
		USART_PrintStr("GW0 - Not set");
	}
	else USART_PrintStr("GW0 - Set");

}
Поправьте меня, если я не прав. Вот такая конструкция может ведь быть индикатором успешной записи в w5100:

Код: Выделить всё

        W5100_Write(GAR + 0,gtw_addr[0]);
	_delay_ms(100);
	
	if(W5100_Read(GAR+0) != gtw_addr[0]) {
		USART_PrintStr("GW0 - Not set");
	}
	else USART_PrintStr("GW0 - Set");
На Вас одна надежда. Чувствую, впадаю в тупку.

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 16:09:37
mail_robot
отдохни денек-другой. Со мной такое тоже бывало. Потом решение приходит как по волшебству. Не зря предки вещали - утро вечера мудреннее

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 16:43:03
Mishany
#include <avr/interrupt.h> вижу
sei(); не нашел.
Сам недавно сталкнулся с SPI режим Master
с прерываниями отказывался работать, убрал прерывания заработало, но есть одно НО после передачи n-быйт МК виснет, т.е. есть функция передачи 20 символов (1-й строки) на дисплей, 4 строки передается на 5 строке мк виснет, пока не победил. (проверял в железе, контролировал LOGIC-U, (USBee))
грешу на while(!(SPSR & (1<<SPIF))); ощущение что SPIF несбрасывается после передачи байта.

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 17:22:55
shilvlad
Mishany писал(а):#include <avr/interrupt.h> вижу
sei(); не нашел.
Сам недавно сталкнулся с SPI режим Master
с прерываниями отказывался работать, убрал прерывания заработало, но есть одно НО после передачи n-быйт МК виснет, т.е. есть функция передачи 20 символов (1-й строки) на дисплей, 4 строки передается на 5 строке мк виснет, пока не победил. (проверял в железе, контролировал LOGIC-U, (USBee))
Это не при делах. Удалить забыл.
Mishany писал(а):грешу на while(!(SPSR & (1<<SPIF))); ощущение что SPIF несбрасывается после передачи байта.
А вот у меня замечена ерунда такая, что виснет на while(!(SPSR & (1<<SPIF))). Причем на произвольных байтах, в произвольных местах. Еще одна загадка.

Re: Atmega8515 + Spi

Добавлено: Пт окт 31, 2014 18:20:44
Mishany
засекал логическим анализатором при передачи 8 битов пропуски тактов
вот пример
СпойлерИзображение
уж не знаю как там на аппаратном уровне все происходит, но может аппаратный счетчик 8-ми тактов не срабатывает?
более наглядно:
СпойлерИзображение
c картинками это я лох :oops: пропусков тактового нет до 4 MHz, анализатор пропускал импульсы поднял разрешение до 4х вместо 2х

Re: Atmega8515 + Spi

Добавлено: Вс ноя 02, 2014 14:06:42
Mishany
у себя обнаружил причину зависаниев нехватка оперативки