Уважаемые гуру, я тут попробовал с SPI поработать и не очень понимаю до чего доработался. Пожалуйста, кто что то подобное делал (без ардуиновской SPI.h) - посмотрите трезвым взглядом, нигде ли я не накосячил? Задача простая: 1. передать команду 0х02 (запись в память) 2. передать 24бита адреса (0х05) 3. передать байт, который пишу в память (128) Затем 1. передать команду 0х03 (чтение из памяти) 2. передать 24бита адреса откуда читаем (0х05) 3. обменяться байтом по SPI и вернуть его в функции Затем Сравнить принятый байт с 128 и если он 128 то мигать светодиодом "1010101010..." а если нет то "100000000100000000" В итоге то у меня сравнение проходит, странным образом это сравнение последнего значения в SPDR и если, к примеру, записать 255 по адресу 0005 а затем 128 по адресу 0006, то сравнение с адреса 0005 с 255 уже не проходит... Мучаю я вот эту микросхемку: https://datasheet.lcsc.com/szlcsc/Microchip-Tech-23LC1024-I-SN_C48388.pdf где черным по белому сказано: Код Код (C++): #include <avr/io.h> #define SPI_PORTX PORTB #define SPI_DDRX DDRB #define SPI_MISO 3 #define SPI_MOSI 2 #define SPI_SCK 1 #define SPI_RAM 5 #define SPI_FLASH 4 void SPI_Init(void){ SPI_DDRX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (0<<SPI_MISO); SPI_PORTX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (1<<SPI_MISO); SPCR = (1<<SPE) | (0<<DORD) | (1<<MSTR) | (0<<CPOL) | (0<<CPHA) | (1<<SPR1) | (0<<SPR0); SPSR = (0<<SPI2X); } void RAM_WriteByte(uint32_t address, uint8_t data){ SPI_PORTX &= ~(1<<SPI_RAM); SPDR = 0x02; //03 - for read while(!(SPSR & (1<<SPIF))); SPDR = address>>24; while(!(SPSR & (1<<SPIF))); SPDR = address>>16; while(!(SPSR & (1<<SPIF))); SPDR = address>>8; while(!(SPSR & (1<<SPIF))); SPDR = data; while(!(SPSR & (1<<SPIF))); SPI_PORTX |= (1<<SPI_RAM); } uint8_t RAM_ReadByte(uint32_t address){ uint8_t report = 0; SPI_PORTX &= ~(1<<SPI_RAM); SPDR = 0x03; while(!(SPSR & (1<<SPIF))); SPDR = address>>24; while(!(SPSR & (1<<SPIF))); SPDR = address>>16; while(!(SPSR & (1<<SPIF))); SPDR = address>>8; while(!(SPSR & (1<<SPIF))); SPDR = report; while(!(SPSR & (1<<SPIF))); report = SPDR; SPI_PORTX |= (1<<SPI_RAM); return report; } void Delay(volatile int n){ for(volatile int m=n;m;--m); } void LED_HIGH(){ PORTC |= (1<<7); //BUILTIN LED ON } void LED_LOW(){ PORTC &= ~(1<<7); //BUILTIN LED OFF } int main(void) { SPI_Init(); DDRC = 255; uint8_t bbb = 0; uint32_t addr = 5; while (1) { RAM_WriteByte(addr,128); bbb = RAM_ReadByte(5); if (bbb == 128){ LED_HIGH(); Delay(65000); LED_LOW(); Delay(65000); } else { LED_HIGH(); Delay(65000); LED_LOW(); Delay(65000); Delay(65000); Delay(65000); Delay(65000); Delay(65000); Delay(65000); Delay(65000); Delay(65000); Delay(65000); Delay(65000); } } }
Я указателями пользуюсь. При этом не надо загонять в стек монстров по 4 байта http://forum.amperka.ru/threads/Суперэкономичный-беспроводной-монитор-Т-и-rh.17221/#post-199941
Спасибо ) Вопрос есть, вы пишете, что У меня пин SS сконфигурирован на выход (PORTB, пятый бит) - (1<<SPI_RAM): Код (C++): SPI_DDRX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (0<<SPI_MISO); я и работаю с чипом памяти как мастер, но для работы мне необходимо 5-й бит PORTB переводить в низкий уровень, что бы заселектить чип памяти как он того требует. Возможно ли что аппаратный SPI в микроконтроллере бросает всё и переключает себя в режим SLAVE?
В качестве пина SS для режима мастер может быть задействован абсолютно любой пин. Но аппаратный пин SS обязательно должен быть сконфигурирован на выход. Можно и на вход, но тогда его подтянуть к плюсу. Если SPI используется как Slave, то пином SS управляется работа SPI - низкий уровень - SPI слушает и записывает биты с линии MOSI. Когда SPI мастер и пин SS используется как вход, то при появлении низкого уровня SPI сразу же (закончена передача текущего байта или нет - ему пофигу) переключает себя в SLAVE. На бракованных кристаллах слышал историю, что низкий уровень на выводе SS также переключает SPI в SLAVE режим. Проверить просто - на линии SCK в SLAVE режиме нет тактирования при попытке передать байт.
Так оно и есть ) Использую PB5 как SS для RAM. Я про это читал, но не придал особого значения ))) Получается, что надо еще Код (C++): // это добавить #define SPI_SS 0 // и тут проинитить на выход SPI_DDRX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_SS) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (0<<SPI_MISO); // и поднять SPI_PORTX |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_SS) | (1<<SPI_RAM) | (1<<SPI_FLASH) | (1<<SPI_MISO); Спасибо огромное, вечером попробую ))
Заработало!!! Теперь у меня в ардуинке есть 128кб памяти, на все хватит! Сам спаял, сам дровишку написал )) Спасибо за науку! Что было: помимо забытого SS я там еще жесточайшим образом с преобразованием адреса с 32bit в 24bit накололся, поэтому запись/чтение всегда шли по нулевому адресу, вызывая столь необычный баг, когда проверку проходит только последнее записанное значение.