CIIAPTAK 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Доброго дня уважаемые... У кого то есть библиотека реализации программного SPI интерфейса на avr? Нужен именно программный, ибо аппаратный уже занят. Да и девайс разведен уже на на другие выводы Мк. Заранее вам благодарен. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mempfis_ 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Нужен именно программный, ибо аппаратный уже занят. Да и девайс разведен уже на на другие выводы Мк. Чтож там сложного то: #define HI(x) SPI_PORT |= (1<<(x)) #define LO(x) SPI_PORT &= ~(1<<(x)) unsigned int SPIWriteWord(unsigned int cmd) { unsigned char i; unsigned int recv; recv = 0; LO(SCK); LO(nSS); for(i=0; i<16; i++) { if(cmd&0x8000) HI(SDI); else LO(SDI); HI(SCK); recv<<=1; if( SPI_PIN&(1<<SDO) ) { recv|=0x0001; } LO(SCK); cmd<<=1; } HI(nSS); return recv; } Обзовите где нибудь выводы SDI, SDO, SCK. Тут 16битный вариант, сли нужно код легко переделывается на 8 бит. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
CIIAPTAK 0 18 октября, 2009 Опубликовано 18 октября, 2009 (изменено) · Жалоба Чтож там сложного то: #define HI(x) SPI_PORT |= (1<<(x)) #define LO(x) SPI_PORT &= ~(1<<(x)) unsigned int SPIWriteWord(unsigned int cmd) { unsigned char i; unsigned int recv; recv = 0; LO(SCK); LO(nSS); for(i=0; i<8; i++) { if(cmd&0x80) HI(SDI); else LO(SDI); HI(SCK); recv<<=1; if( SPI_PIN&(1<<SDO) ) { recv|=0x0001; } LO(SCK); cmd<<=1; } HI(nSS); return recv; } Биг спс. Для 8 ми битного, правильно поправил? =) Это на запись. А как на чтение? В случае двухстороннего обмена. Изменено 18 октября, 2009 пользователем CIIAPTAK Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prottoss 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Это на запись. А как на чтение? В случае двухстороннего обмена.Мда, тяжелый случай:) Так это оно и есть - загоняете в функцию байт для записи, автоматом функция вернула то, что прочитала. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 45 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба SPI куда элегантнее программировать на ассемблере, если аппаратно этого сделать по каким-то причинам нельзя. Элегантность заключена в том, что так можно эффективно использовать флаг переноса при сдвигах, строго выдержать меандр по времени (хотя последнее, обычно, не требуется) и сделать правильные задержки. На чистом С такое написать нельзя. Здесь приведены сочиненные мной процедуры: void Wr_Reg( char byte); // запись по SPI в регистр АЦП char Rd_Reg( void); // чтение по SPI регистра АЦП Вся остальная программа у меня на С, откуда я и вызываю функции Wr_Reg(byte) и Rd_Reg(). Их описание в хидере я только что привела, их тела на ассемблере выглядят так: RSEG CODE:CODE:NOROOT(1) PUBLIC Wr_Reg Wr_Reg: ldi R17, 8 LoopWrReg: sbi PORTD, SCLK; установим SCLK в 1 rol R16; сдвигаем регистр brcs SetSDI cbi PORTD, SDI; SDI = 0 rjmp CliSCLK; 2 clocks SetSDI: sbi PORTD, SDI; SDI = 1 nop; 1+1 clocks nop CliSCLK: cbi PORTD, SCLK; установим SCLK в 0 dec R17 brne LoopWrReg; если не 0 ret PUBLIC Rd_Reg Rd_Reg: ldi R17, 8 clr R16; обнуляем регистр LoopRdReg: sbi PORTD, SCLK; установим SCLK в 1 nop cbi PORTD, SCLK; установим SCLK в 0 lsl R16; сдвигаем регистр sbic PIND, SDO; SDO ? ori R16, 1; устанавливаем мл.бит dec R17 brne LoopRdReg; если не 0 ret Связь осуществляется через порт D, который можно заменить на любой другой. SDI, SDO и SCLK по назначению соответствуют MOSI, MISO и СLK. Суть не меняется, если вместо АЦП будет какое-то другое устройство. P.S. Проект на IAR EWAVR, в котором имеется один ассемблерный файл (этот), а остальные на C. Микроконтроллер ATtiny2313. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба В тексте программы ничего нету про SDO. Поправьте, плз, чтоб студенты не ошибались:) И еще (для страшных эстетов) - некая зависимость от тактовой частоты проца. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 45 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба В тексте программы ничего нету про SDO. Поправьте, плз, чтоб студенты не ошибались:) Поправила. И еще (для страшных эстетов) - некая зависимость от тактовой частоты проца. Да-да! Это очень важно! И вовсе не для эстетов. В ассеблерную процедеру есть возможноть натолкать столько nop (пустых операций), чтобы сделать любую дополнительную задержку. Это очень даже может понадобится тогда, когда МК работает на более высокой частоте кварца, чем необходимо, чтобы соблюсти требования ведомого устройства. И тут дело не только в частоте его кварца, сколько в технических требованиях к обмену. Это весьма типичная задача при работе с АЦП, в даташите которых расписаны тайминги на SPI обмен. Ассемблер очень хорош как раз для соблюдения всех этих таймингов и латентного времени между передачей команды и приемом данных. Однако смысл имеет писать на ассемблере только такую интерфейсную часть программы. Полностью переходить на ассемлер не советую - ошибки на нем совершаются гораздо чаще, чем на C, и программировать на нем медленнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба SPI куда элегантнее программировать на ассемблере... А откомпилировать несколько сишных строк и посмотреть на результат было нельзя? есть возможноть натолкать столько nop (пустых операций) __no_operation(); или asm ( "NOP" ); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
prottoss 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Вот мой вариант софтового/железного SPI, с задержками без всякого ассемблера. /***************************************************************************** Обмен данными по SPI записывает в SPI порт данные wr_data и возвращает прочитанные при обмене данные ******************************************************************************/ UCHAR ExSPI(UCHAR wr_data) { // проверяем джампер low_sck if(ISP_PIN & (1 << PIN_LOW_SCK)) // не замкнут, аппаратный SPI { SPI_ON(); // включаем SPI SPDR = wr_data; // загружаем SPI данными while(!(SPSR & (1<<SPIF))){}; // ждем окончания передачи return SPDR; // возвращаем принятые данные } else // иначе софтверный SPI { UCHAR rd_data; SPI_OFF(); // выключаем аппаратный SPI for(UCHAR i = 0; i < 8; i++) { // отправляем старший бит отправляемого байта if(0 != (wr_data & 0x80)) ISP_PORT |= (1 << PIN_MOSI); // = 1 else ISP_PORT &= ~(1 << PIN_MOSI); // = 0 // подготавливаем следующий бит wr_data <<=1; // принимаем очередной (начиная со старшего) бит // принимаемого байта rd_data <<= 1; if(0 != (ISP_PIN & (1 << PIN_MISO))) rd_data++; // устанавливаем единичный бит, если высокий принимаемый уровень // формируем импульс на выводе SCK МК ISP_PORT |= (1 << PIN_SCK); // высокий __delay_cycles(LOW_SCK_DELEY); // задержка ISP_PORT &= ~(1 << PIN_SCK); // низкий __delay_cycles(LOW_SCK_DELEY); // задержка } return rd_data; } } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 45 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба А откомпилировать несколько сишных строк и посмотреть на результат было нельзя? __no_operation(); или asm ( "NOP" ); На языке С даже задачу нельзя сформулировать так, чтобы его компилятор сгенерировал код подобной плотности. Причина в том, что понятие флагов переноса или переполнения на этом языке никак не отражено. А следовательно и воспользваться этим удобным механизмом нет возможности. Натолкать задержек, конечно же, язык С позволяет. И не только указанным вами способом, но и вообще любого иного рода мусорным кодом. Приведенный мною пример близок к наиболее ускоренному варианту. Nop используется для "проработки" фронта импульса, который при комбинации соседних команд "поднять и опустить" зачастую не достигает максимально возможного значения (толи ёмкости мешают, толи еще что). Я не думаю, что длительное смотрение в откомпилированный результат позволит вам написать код на С, который работает быстрее, но в тоже время был бы полностью надежен. На С такие вещи пишут только тогда, когда торопиться некуда. Этот же код можно использовать даже в прерывании! (хотя и не рекомендуется). Не перевелись еще любители опрашивать АЦП прямо в той процедуре обработки прерывания, которое возникает от сигнала готовности данных DREADY. Вот мой вариант софтового/железного SPI, с задержками без всякого ассемблера. В этой теме никого ваш вариант не интересует. В начальном сообщении четко сформулирована задача - аппаратный SPI не использовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Я не думаю... Я же не просил Вас думать :( я просил просто откомпилировать, что-то вроде void Wr_Reg( unsigned char cmd ) { for( char i=8; i; i-- ) { (cmd & 0x80) ? ( HI( MOSI ) ) : ( LO( MOSI ) ); HI( SCK ); cmd <<= 1; LO( SCK ); } } и посмотреть, что там с "кодом подобной плотности"... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Xenia 45 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Я же не просил Вас думать :( я просил просто откомпилировать, что-то вроде ... и посмотреть, что там с "кодом подобной плотности"... У вас "лишняя" проверка cmd & 0x80, т.к. тестировать быстрее при сдвиге cmd <<= 1, поскольку этот бит выпадающий. К другим недостаткам вашего кода можно отнести отсутствие однотактной задержки между установкой MOSI и подачей клока SCK. Здесь желательно тоже пропустить один такт, чтобы MOSI успел достичь своего максимального или минимального значения. И вообще, потуги вроде ваших :), возникают исключительно вследствии того, что вы знаете, какой должна быть данная процедура в кодах МК, но пыжитесь достигнуть этого, укрощая С. В таких случаях было бы более эффективно, если бы вы воплощали свое знание сразу на том языке (в данном случае ассемблере), который плозволяет учитывать все необходимые нюансы. А так вы вместо этого боретесь с языком С, пытаясь подогнать его под требуемую ассемлерную кодировку. Язык должен быть помощником, не противником. Не стоит мучить С, чтобы он выдавал тот код, который без напряга можно было бы написать на ассеблере. А на языке С пишут обычно то, в отношении чего у вас не будет в дальнейшем притензий к компилятору. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба У вас "лишняя" проверка.... Ближе к делу, т.е. поминаемой Вами "плотности кода". Сколько команд получили из сишного исходника и насколько это "не плотнее" зачем-то писанного на ASM. И вообще, потуги вроде ваших , возникают исключительно вследствии того, что вы знаете, какой должна быть данная процедура в кодах МК Потуги??? Абсолютно в лоб писанный сишный исходник. Какой должна в кодах MK мне по барабану - я пишу на в данном случае на 'C' тупейший алгоритм банального ногомахания и с трудом представляю,как можно на 'C' зачем-то написать по другому. Я даже, то что написал не компилировал ввиду полной для меня очевидности получения абсолютно приемлимого кода из под IAR компилятора. отсутствие однотактной задержки между установкой MOSI и подачей клока SCK Прочитайте предыдущий пост и добавьте сколько и куда хотите. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба Язык должен быть помощником, не противником. Просто откомпильте - никакого оверхеда там не полУчите. Уже не те времена на дворе, чтоб было стыдно за компиляторы в таких простых ситуациях. А отсутствие операций с битом переноса - это только оттого, что операция типа sbrc Rx,7 ничуть не хуже. Необходимость в использовании бита переноса при приеме последовательных данных у меня лично возникала, но это было в другом контексте - когда читается capture register и полученное значение сравнивается с константой, соотвествующей некой центральной частоте. В общем, это совсем из оффтопа. По поводу НОПов - имхо достаточно в асме проверку #if(F_CPU > 8000000UL) сделать (как там по-ИАРовски - не уверен, но в winavr сделал бы так) - и добавить один лишний НОП Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 18 октября, 2009 Опубликовано 18 октября, 2009 · Жалоба У вас "лишняя" проверка cmd & 0x80, т.к. тестировать быстрее при сдвиге cmd <<= 1, поскольку этот бит выпадающий.Это смотря чего хотеть. Если скважности SCK 2.000 и предельно точной настройки частоты, то да, лучше асм. Если "лишь бы более-менее близко к 2 и побыстрее", то это пишется левой задней, быстрее заново написать, чем искать откуда скопипастить, так как писалось уже неоднократно, в том числе ещё для 51-го. Да, в зависимости от данных слегка дрожит длительность 1-ки. Что-то не могу придумать пример, где это будет мешать. Зато одна процедура и на ввод, и на вывод, довольно компактно и быстро. #include <avr/io.h> #include "pin_macros.h" #define SCK B,0,H #define MOSI B,1,H #define MISO B,2,H /* ну и где-то в h-файле, если кого-то "полнота набора" волнует * static inline uint8_t spi_in(void) { retuirn spi_io(0xFF); } * static inline void spi_out(uint8_t b) { spi_io(b); } */ /* Это под SPI, у которого сдвиг по спаду, приёмник фиксирует по фронту, ну * данная подпрограмма - после фронта, лишь бы до спада. */ uint8_t spi_io(uint8_t b) { uint8_t i = 8; do { OFF(SCK); OFF(MOSI); if(b & 0x80) ON(MOSI); b <<= 1; // а вот она задержка от выдачи до фронта ON(SCK); if( ACTIVE(MISO) ) ++b; } while(--i); OFF(SCK); return b; } И компилируется в такое .global spi_io .type spi_io, @function spi_io: /* prologue: frame size=0 */ /* prologue end (size=0) */ ldi r25,lo8(8) .L2: cbi 56-0x20,0 ; SCK = 0 cbi 56-0x20,1 ; MOSI = 0 sbrc r24,7 sbi 56-0x20,1 ; MOSI = 1 если надо .L3: lsl r24 ; задержка перед фронтом sbi 56-0x20,0 ; SCK = 1 sbic 54-0x20,2 ; семплирование входа subi r24,lo8(-(1)) .L5: subi r25,lo8(-(-1)) brne .L2 cbi 56-0x20,0 ldi r25,lo8(0) /* epilogue: frame size=0 */ ret Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться