Хочу связать ATMega 2561 и флеш-память AT45DB041A через SPI.
На данном этапе хочу хотя бы считать состояние регистр статуса.
Но не работает.
Помогите плиз!
- Вложения
-
- spi.RAR
- (235.09 КБ) 422 скачивания
Код: Выделить всё
//-------------------------------------------------------------------------------------------------
uint8_t flash_spi_io(uint8_t data)
{
uint8_t bit_number;
for (bit_number = 8; bit_number-- > 0;)
{
Pin_AT45DB_CLK_OFF();
if ((data & 0x80) == 0x80)
Pin_AT45DB_MOSI_ON();
Pin_AT45DB_CLK_ON();
data <<= 1;
if (Pin_AT45DB_MISO_SIGNAL() != 0x00)
data |= 1;
Pin_AT45DB_MOSI_OFF();
}
return data;
}
//-------------------------------------------------------------------------------------------------
uint8_t flash_read_status_register(void)
{
uint8_t status;
Pin_AT45DB_CS_ON();
flash_spi_io(CMD_STATUS_REGISTER_READ);
status = flash_spi_io(0);
Pin_AT45DB_CS_OFF();
return status;
}
Код: Выделить всё
;PB0 - SS
;PB1 - SCLK
;PB2 - MOSI
;PB3 - MISO
; Установка MOSI и SCK на вывод, все остальные на ввод
ldi r19,(0<<PB3)|(1<<PB2)|(1<<PB1)|(0<<PB0)
out DDRB,r18
SS на флеш памяти идет с инверсией. Сначала устанавливаем SS в 1. До посылки байта его в 0 - а после в 1. Правильно?Engineer_Keen писал(а):Почему SS (PB0) на ввод? AT45 принимает команды по SPI при низком уровне SS, им должен управлять контроллер!Код: Выделить всё
;PB0 - SS ;PB1 - SCLK ;PB2 - MOSI ;PB3 - MISO ; Установка MOSI и SCK на вывод, все остальные на ввод ldi r19,(0<<PB3)|(1<<PB2)|(1<<PB1)|(0<<PB0) out DDRB,r18
Так что во первых: 1<<PB0 в DDRB (и сразу этот же пин в единицу в PORTB)
Во вторых: перед началом обмена по SPI - CBI PORTB,PB0, после окончания приема/передачи - SBI PORTB,PB0.
Пока что все...
Опередили... Ну зато у меня ассемблер
Пардон, не понял. Т. е. помимоEngineer_Keen писал(а):Так что во первых: 1<<PB0 в DDRB (и сразу этот же пин в единицу в PORTB)Код: Выделить всё
ldi r19,(0<<PB0) out DDRB,r19
ДаSlavast писал(а): Сначала устанавливаем SS в 1. До посылки байта его в 0 - а после в 1. Правильно?
Здрасьте приехали... У вас же уже есть 2 отдельные процедуры, одна для записи (SPI_MasterTransmit), одна для чтения (SPI_MasterReceive). Послали сколько надо, прочитали сколько надо, чего переключать-то?Slavast писал(а): У меня еще тут Оооочень важный вопрос? А как переключать наш контроллер в режим чтения?
Нам же нужно со старта программы держать высокий уровень на SS пока не начался процесс обмена по SPI.Slavast писал(а): Т. Е непосредственно единицу на сам порт этого пина?
Engineer_Keen писал(а):Slavast писал(а): Сначала устанавливаем SS в 1. До посылки байта его в 0 - а после в 1. Правильно?
Спасибо. А есть такой же примерно код на ассемблере?Zheleznjakov писал(а):чет хлопотно асм ковырять, типичная ошибка при работе с данной флехой забывают дергать чип селектом
вот рабочий код, правда на си (и не через апаратный spi)не забыть про инверсию на чип селектКод: Выделить всё
Когда мы начинаем передавать данные по SPI, МК сам ставит сигналы MOSI и SCK в нужные состояния (при настройке SPI задается режим 0 или 3). Но пином SS (лииня CS) он не управляет. Управлять линией CS можно вообще с любого свободного пина МК, и делается это программно, особенно если на SPI сидит более одного устройства.Slavast писал(а): Вот тут и непонятно: MOSI и SCK нужно задавать в 1 на DDRB или PORTB (т.е. указывать только направление или в заранее заданном на выход порт выдавать 1 или 0)? Это же ведь существенно! В Си коде за этим не могу уследить. Точно также и SS - нужно 1 посылать в DDRB или PORTB?
Код: Выделить всё
ReadWord:
CBI PORTA,PA3 ;CS low
LDI r16,0x03 ;0x03 - read EEPROM
RCALL SPIOUT ;write instruction
MOV r16,adrS01
RCALL SPIOUT ;write high adr. byte
MOV r16,adrS02
RCALL SPIOUT ;write mid adr. byte
MOV r16,adrS03
RCALL SPIOUT ;write low adr. byte
RCALL SPIOUT ;read data
STS SND00,R16
RCALL SPIOUT ;read data
STS SND01,R16
SBI PORTA,PA3 ;CS high
RET
SPIOUT: ;fastest possible out via USI
OUT USIDR,r16 ;send byte to SPI data register
LDI r16,(1<<USIWM0)|(0<<USICS0)|(1<<USITC) ;clk=0
LDI r17,(1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK) ;clk=1
OUT USICR,r16
OUT USICR,r17 ;clock 1
OUT USICR,r16
OUT USICR,r17 ;clock 2
OUT USICR,r16
OUT USICR,r17 ;clock 3
OUT USICR,r16
OUT USICR,r17 ;clock 4
OUT USICR,r16
OUT USICR,r17 ;clock 5
OUT USICR,r16
OUT USICR,r17 ;clock 6
OUT USICR,r16
OUT USICR,r17 ;clock 7
OUT USICR,r16
OUT USICR,r17 ;clock 8
IN r16,USIDR ;read byte from SPI data register
RET
к сожалению нет.Slavast писал(а):Спасибо. А есть такой же примерно код на ассемблере?Zheleznjakov писал(а):чет хлопотно асм ковырять, типичная ошибка при работе с данной флехой забывают дергать чип селектом
вот рабочий код, правда на си (и не через апаратный spi)не забыть про инверсию на чип селектКод: Выделить всё
Ресет на флеш подается вместе с ресетом на МК.Zheleznjakov писал(а):Ну как говорится "Чудес не бывает!"
Ошибки возможны ведь не только в программе но и в железе
Приведите схему включения, фото платы или ещё что.
Что с ресетом у вас? (какой уровень подали)
Код: Выделить всё
www1:
lds r23, UCSR0A
SBRS r23,UDRE0 ; Пропуск если нет флага готовности,
; если 1 - то готов отправлять данные
RJMP www1 Код: Выделить всё
WWW1:
SBIS UCSR0A,UDREN
RJMP WWW1www2:Engineer_Keen писал(а):Почему в процедуре вывода по UART стоит STS, а не OUT?
PS: настройки SPI/UART не проверял. Модифицированный (AT25 вместо AT45, команда RDID вместо 0хD7) вариант проверен в симуляторе - работает.

Код: Выделить всё
void SPI_MasterTransmit(char cData)
{
PORTB=(0<<PORTB0); //переход с высого уровня на назкий (SS)
/* Запуск передачи данных */
SPDR = cData;
/* Ожидание завершения передачи данных */
while(!(SPSR & (1<<SPIF)));
input=SPDR;
PORTB=(1<<PORTB0);
}Код: Выделить всё
#include <mega128.h>
#include <stdio.h>
#include <delay.h>
// Alphanumeric LCD functions
#asm
.equ __lcd_port=0x15 ;PORTC // Для изменения порта подключения вставляем вместо .equ __lcd_port=0x15 ;PORTC (исходя из даташита стр. Register Summary)
#endasm // .equ __lcd_port=0x1B ;PORTA или .equ __lcd_port=0x18 ;PORTB или .equ __lcd_port=0x12 ;PORTD (даташит atmega16)
#include <lcd.h>
char x;
int input;
// LCD
//
char lcd_buffer[33];
unsigned char data;
int temp;
void SPI_MasterInit(void)
{
/* Установка MOSI и SCK на вывод, все остальные на ввод */
DDRB = (1<<DDB2)|(1<<DDB1)|(1<<DDB0); // 1<<DDB0 для SS
/* Разрешение SPI в режиме мастера, установка скорости связи fck/16
*/SPCR = (0<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
}
void SPI_MasterTransmit(char cData)
{
PORTB=(0<<PORTB0); //переход с высого уровня на назкий (SS)
/* Запуск передачи данных */
SPDR = cData;
/* Ожидание завершения передачи данных */
while(!(SPSR & (1<<SPIF)));
input=SPDR;
PORTB=(1<<PORTB0);
}
void lcd_show(void)
{
lcd_gotoxy(0,1);
sprintf(lcd_buffer,"x=%u",input);
lcd_puts(lcd_buffer);
}
void main(void)
{
PORTF=0;
DDRF=0xFF;
// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=Out Bit1=Out Bit0=Out
PORTB=(1<<PORTB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=0 Bit1=0 Bit0=0
//PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (1<<PORTB0);
// SPI initialization
// SPI Type: Master
// SPI Clock Rate: 2000,000 kHz
// SPI Clock Phase: Cycle Start
// SPI Clock Polarity: Low
// SPI Data Order: MSB First
//SPCR=(1<<SPIE) | (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);
//SPSR=(0<<SPI2X);
// Clear the SPI interrupt flag
#asm
in r30,spsr
in r30,spdr
#endasm
x=4;
// Global enable interrupts
#asm("sei")
lcd_init( 16 );
SPI_MasterInit();
SPI_MasterTransmit(0x15);
SPI_MasterTransmit(0xF);
SPI_MasterTransmit(0xA);
lcd_show();
while (1)
{
}
}
Код: Выделить всё
PORTB=(0<<PORTB0); //переход с высого уровня на назкий (SS)
SPI_MasterTransmit(0x15);
SPI_MasterTransmit(0xFF);
SPI_MasterTransmit(0xFF);
PORTB=(1<<PORTB0);