реклама на сайте
подробности

 
 
> Программный SPI, реализация на avr
CIIAPTAK
сообщение Oct 18 2009, 13:09
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 22-07-07
Пользователь №: 29 290



Доброго дня уважаемые...
У кого то есть библиотека реализации программного SPI интерфейса на avr?

Нужен именно программный, ибо аппаратный уже занят. Да и девайс разведен уже на на другие выводы Мк.

Заранее вам благодарен.
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
mempfis_
сообщение Oct 18 2009, 13:27
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409



Цитата(CIIAPTAK @ Oct 18 2009, 16:09) *
Нужен именно программный, ибо аппаратный уже занят. Да и девайс разведен уже на на другие выводы Мк.


Чтож там сложного то:

Код
#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 бит.
Go to the top of the page
 
+Quote Post
CIIAPTAK
сообщение Oct 18 2009, 13:59
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 27
Регистрация: 22-07-07
Пользователь №: 29 290



[quote name='mempfis_' date='Oct 18 2009, 17:27' post='663748']
Чтож там сложного то:

Код
#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 ми битного, правильно поправил? =)
Это на запись. А как на чтение? В случае двухстороннего обмена.

Сообщение отредактировал CIIAPTAK - Oct 18 2009, 14:05
Go to the top of the page
 
+Quote Post
prottoss
сообщение Oct 18 2009, 14:25
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659



Цитата(CIIAPTAK @ Oct 18 2009, 21:59) *
Это на запись. А как на чтение? В случае двухстороннего обмена.
Мда, тяжелый случайsmile.gif Так это оно и есть - загоняете в функцию байт для записи, автоматом функция вернула то, что прочитала.


--------------------
Go to the top of the page
 
+Quote Post
Xenia
сообщение Oct 18 2009, 15:04
Сообщение #5


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



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.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 18 2009, 15:45
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Xenia @ Oct 18 2009, 18:04) *
SPI куда элегантнее программировать на ассемблере...

А откомпилировать несколько сишных строк и посмотреть на результат было нельзя?
Цитата
есть возможноть натолкать столько nop (пустых операций)

__no_operation();
или
asm ( "NOP" );


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Xenia
сообщение Oct 18 2009, 16:06
Сообщение #7


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(zltigo @ Oct 18 2009, 19:45) *
А откомпилировать несколько сишных строк и посмотреть на результат было нельзя?

__no_operation();
или
asm ( "NOP" );

На языке С даже задачу нельзя сформулировать так, чтобы его компилятор сгенерировал код подобной плотности. Причина в том, что понятие флагов переноса или переполнения на этом языке никак не отражено. А следовательно и воспользваться этим удобным механизмом нет возможности.

Натолкать задержек, конечно же, язык С позволяет. И не только указанным вами способом, но и вообще любого иного рода мусорным кодом.
Приведенный мною пример близок к наиболее ускоренному варианту. Nop используется для "проработки" фронта импульса, который при комбинации соседних команд "поднять и опустить" зачастую не достигает максимально возможного значения (толи ёмкости мешают, толи еще что).

Я не думаю, что длительное смотрение в откомпилированный результат позволит вам написать код на С, который работает быстрее, но в тоже время был бы полностью надежен. На С такие вещи пишут только тогда, когда торопиться некуда. Этот же код можно использовать даже в прерывании! (хотя и не рекомендуется). Не перевелись еще любители опрашивать АЦП прямо в той процедуре обработки прерывания, которое возникает от сигнала готовности данных DREADY.

Цитата(prottoss @ Oct 18 2009, 19:56) *
Вот мой вариант софтового/железного SPI, с задержками без всякого ассемблера.

В этой теме никого ваш вариант не интересует. В начальном сообщении четко сформулирована задача - аппаратный SPI не использовать.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Oct 18 2009, 16:08
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Xenia @ Oct 18 2009, 19:03) *
Я не думаю...

Я же не просил Вас думать sad.gif я просил просто откомпилировать, что-то вроде
Код
void Wr_Reg( unsigned char cmd )
{
    for( char i=8; i; i-- )
      {    (cmd & 0x80) ? ( HI( MOSI ) ) : ( LO( MOSI ) );
        HI( SCK );
        cmd <<= 1;
        LO( SCK );
      }
}

и посмотреть, что там с "кодом подобной плотности"...


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Xenia
сообщение Oct 18 2009, 16:27
Сообщение #9


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(zltigo @ Oct 18 2009, 20:08) *
Я же не просил Вас думать sad.gif я просил просто откомпилировать, что-то вроде
...
и посмотреть, что там с "кодом подобной плотности"...

У вас "лишняя" проверка cmd & 0x80, т.к. тестировать быстрее при сдвиге cmd <<= 1, поскольку этот бит выпадающий.
К другим недостаткам вашего кода можно отнести отсутствие однотактной задержки между установкой MOSI и подачей клока SCK. Здесь желательно тоже пропустить один такт, чтобы MOSI успел достичь своего максимального или минимального значения.

И вообще, потуги вроде ваших smile.gif, возникают исключительно вследствии того, что вы знаете, какой должна быть данная процедура в кодах МК, но пыжитесь достигнуть этого, укрощая С. В таких случаях было бы более эффективно, если бы вы воплощали свое знание сразу на том языке (в данном случае ассемблере), который плозволяет учитывать все необходимые нюансы. А так вы вместо этого боретесь с языком С, пытаясь подогнать его под требуемую ассемлерную кодировку. Язык должен быть помощником, не противником. Не стоит мучить С, чтобы он выдавал тот код, который без напряга можно было бы написать на ассеблере. А на языке С пишут обычно то, в отношении чего у вас не будет в дальнейшем притензий к компилятору.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Oct 18 2009, 18:22
Сообщение #10


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(Xenia @ Oct 18 2009, 19:27) *
У вас "лишняя" проверка 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


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- CIIAPTAK   Программный SPI   Oct 18 2009, 13:09
||- - _Pasha   Цитата(Xenia @ Oct 18 2009, 18:04) В тек...   Oct 18 2009, 15:15
|||- - Xenia   Цитата(_Pasha @ Oct 18 2009, 19:15) В тек...   Oct 18 2009, 15:37
|||- - prottoss   Цитата(Xenia @ Oct 18 2009, 23:37) Вот мо...   Oct 18 2009, 15:56
||- - zltigo   Цитата(Xenia @ Oct 18 2009, 19:27) У вас ...   Oct 18 2009, 16:41
||- - _Pasha   Цитата(Xenia @ Oct 18 2009, 19:27) Язык д...   Oct 18 2009, 16:56
|- - mempfis_   КодБиг спс. Для 8 ми битного, правильно поправил? ...   Oct 19 2009, 07:13
- - Rst7   Кстати, как по мне, все это очень медленно Если и...   Oct 18 2009, 18:30
|- - Xenia   Цитата(Rst7 @ Oct 18 2009, 22:30) Кстати,...   Oct 18 2009, 19:15
- - Rst7   ЦитатаТак и я о том, Причем тут "и я"? ...   Oct 18 2009, 21:17


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 24th July 2025 - 12:21
Рейтинг@Mail.ru


Страница сгенерированна за 0.01484 секунд с 7
ELECTRONIX ©2004-2016