|
Готовность SPI, как определить? |
|
|
3 страниц
1 2 3 >
|
 |
Ответов
(1 - 30)
|
May 20 2008, 08:23
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(777777 @ May 20 2008, 12:00)  Как определить, что в SPDR можно писать очередной байт? SPIF устанавливается после передачи, но после обработки сбрасывается, и при включении там 0. А есть ли какой бит, по которому можно определить, что передача в данный момент не идет? Т.е. который устанавливается сразу после записи в SPDR? ИМХО, ни как, но если очень надо, заведите свой флаг который будете выставлять перед записью в SPDR и сбрасывать после чтения SPIF из SPSR.
|
|
|
|
|
May 20 2008, 09:38
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(777777 @ May 20 2008, 12:00)  Как определить, что в SPDR можно писать очередной байт? SPIF устанавливается после передачи, но после обработки сбрасывается, и при включении там 0. А есть ли какой бит, по которому можно определить, что передача в данный момент не идет? Т.е. который устанавливается сразу после записи в SPDR? Чего-то напутано. "Сразу после записи в SPDR" передача как раз идёт. Если записать в SPDR пока передача идёт, поднимется флаг WCOL. Писать в SPDR можно через 34 цикла процессора после предыдущей записи (SPCR=0x50). Раньше - синхроимпульсы будут, а данные - нет. Прямо сейчас этим занимаюсь, Мега16. AVR Studio всё правильно симулирует.
|
|
|
|
|
May 20 2008, 13:01
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(777777 @ May 20 2008, 14:45)  Вот я и хочу узнать, когда она закончится. Не используя прерываний, по готовности. Похоже, только читая SPIF и ожидая когда он исчезнет.
А хотелось бы наоборот: перед записью узнать что предыдущая передача уже завершилась, записать SPDR и продолжить заниматься другими делами. "перед записью узнать что предыдущая передача уже завершилась" Как? "читая SPIF". Прочитали - узнали - не завершилась. Что делать? "читая SPIF и ожидая когда он исчезнет". Ну или прерывание скажет, когда.
|
|
|
|
|
May 20 2008, 13:41
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(777777 @ May 20 2008, 09:45)  Похоже, только читая SPIF и ожидая когда он исчезнет А по-моему, наоборот, флаг SPIF появится, когда закончится передача текущего байта. Для самого первого раза (после подачи питания) можно передать фиктивную посылку, чтобы взвести флаг SPIF. Цитата(777777 @ May 20 2008, 09:45)  А хотелось бы наоборот: перед записью узнать что предыдущая передача уже завершилась, записать SPDR и продолжить заниматься другими делами Делаете, как описано выше, потом проверяете флаг SPIF, если он установлен, то записываете в SPDR новый байт на передачу, при этом флаг SPIF сбросится. Цитата(Maik-vs @ May 20 2008, 08:38)  Писать в SPDR можно через 34 цикла процессора после предыдущей записи (SPCR=0x50). Раньше - синхроимпульсы будут, а данные - нет Откуда вы взяли про 34 цикла, ссылочкой не поделитесь? И что такое SPCR=0x50, в нём вроде используются только 0, 6 и 7 биты?
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
May 20 2008, 16:26
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(=GM= @ May 20 2008, 17:41)  А по-моему, наоборот, флаг SPIF появится, когда закончится передача текущего байта. Для самого первого раза (после подачи питания) можно передать фиктивную посылку, чтобы взвести флаг SPIF. конечно после окончания передачи, и поэтому буз внешнего флага здесь не обойтись. Ну типа так он устроен... Цитата Откуда вы взяли про 34 цикла Ну это почти правда, только там не 34 ну и для других делителей будет другое количество тактов, сам пробовал в железе только для X2 режима, но с Вами поделюсь инфой только после того как Вы раскажите/покажите вариант про который мы долго и упорно спорили(PWM на 24 канала)
|
|
|
|
|
May 20 2008, 16:55
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(singlskv @ May 20 2008, 15:26)  конечно после окончания передачи, и поэтому без внешнего флага здесь не обойтись. Ну типа так он устроен... Ну это почти правда, только там не 34 Я и так знаю, что там не 34. Как устроен спи внутри, к сожалению, не знаю. Что такое внешний флаг, не понимаю, о чём вы? То, что я сказал насчёт первого фиктивного байта правильно, но можно обойтись и без его передачи. Если уж взялись отвечать за другого, так и отвечайте нормально, а не наводите тень на плетень (:-). Повторю ещё раз: "Откуда вы взяли про 34 цикла, ссылочкой не поделитесь? И что такое SPCR=0x50, в нём вроде используются только 0, 6 и 7 биты?" Цитата(singlskv @ May 20 2008, 15:26)  сам пробовал в железе только для X2 режима, но с Вами поделюсь инфой только после того как Вы раскажите/покажите вариант про который мы долго и упорно спорили (PWM на 24 канала) Sulking, are we (:-)? Напомните, подзабыл я, и вроде бы с вами не спорил, тем более долго и упорно, поскольку вы были не в теме.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
May 20 2008, 17:29
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(=GM= @ May 20 2008, 20:55)  Я и так знаю, что там не 34. Как устроен спи внутри, к сожалению, не знаю. Что такое внешний флаг, не понимаю, о чём вы? просто переменная в памяти которая будет говорить всем что SPI в данный момент занят Цитата То, что я сказал насчёт первого фиктивного байта правильно, но можно обойтись и без его передачи. А вот здесь я уже недопонял... Цитата Если уж взялись отвечать за другого, так и отвечайте нормально, а не наводите тень на плетень (:-). Повторю ещё раз: "Откуда вы взяли про 34 цикла, ссылочкой не поделитесь? И что такое SPCR=0x50, в нём вроде используются только 0, 6 и 7 биты?" Sulking, are we (:-)? Напомните, подзабыл я, и вроде бы с вами не спорил, тем более долго и упорно, поскольку вы были не в теме. Да ни вапрос, в отличии от Вас готов просто показать код...  Код SPDR = OutHi; // старшая часть выходов 758: 6f b8 out 0x0f, r6; 15 ... __asm__ __volatile__ ("nop"); // бездельничаем пока передается байт __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); __asm__ __volatile__ ("nop"); 776: 00 00 nop Ch2Hi = SPSR; // читаем для сброса флага 778: 2e b0 in r2, 0x0e; 14 Ch2Hi = SPDR; // читаем старшие 8 бит канала2 77a: 2f b0 in r2, 0x0f; 15 но это для X2 режима...
|
|
|
|
|
May 20 2008, 19:36
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(singlskv @ May 20 2008, 21:29)  Код ... __asm__ __volatile__ ("nop"); // бездельничаем пока передается байт но это для X2 режима... Так весь смысл в том, чтоб вместо бездельничья занять контроллер чем то более полезным. Например при подключении индикатора по SPI, где ответа нет. Я делаю с передачей холостого байта при неактивном /cs. Положил в SPDR и пошел готовить следующие данные. Как обойтись без холостой записи надеюсь подскажет GM. А вообще в этом плане хорошо использовать USART в тех контроллерах, в которых есть этот режим. Там получается буферизация записи и можно по паре байт отправлять за один раз. Ну и с флагами там все не так запущено...
|
|
|
|
|
May 20 2008, 20:04
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Qwertty @ May 20 2008, 23:36)  Так весь смысл в том, чтоб вместо бездельничья занять контроллер чем то более полезным. Ну... это был просто пример для разяснения того как работает SPI, хотя пример был из рабочей проги ....  Ну типа иногда(если нет других дел), выгоднее просто ничего не делать... Цитата Например при подключении индикатора по SPI, где ответа нет. Я делаю с передачей холостого байта при неактивном /cs. А вот это мне все-таки кто-нить объясните, что за холостой байт который Многим нужен ?
|
|
|
|
|
May 20 2008, 21:50
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(singlskv @ May 21 2008, 00:04)  А вот это мне все-таки кто-нить объясните, что за холостой байт который Многим нужен ? Про это выше написано - холостая посылка, только для взвода SPIF. Просто записать в SPDR что попало, при неактивных cs. Я пишу сразу после настройки SPI. Далее примерно так: Код void TransmitSPI(uint8_t _data_) { while(!(SPSR & (1<<SPIF))); SPDR = _data_; // Завершения не ждем. }
|
|
|
|
|
May 20 2008, 21:59
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(Qwertty @ May 21 2008, 01:50)  Про это выше написано - холостая посылка, только для взвода SPIF. Просто записать в SPDR что попало, при неактивных cs. Я пишу сразу после настройки SPI. Далее примерно так: Спасибо, теперь понял о чем речь, просто для меня такой вариант не очень применим, поэтому и не мог никак въехать про какую такую холостую посылку речь.
|
|
|
|
|
May 21 2008, 12:49
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(=GM= @ May 20 2008, 17:41)  Откуда вы взяли про 34 цикла, ссылочкой не поделитесь? И что такое SPCR=0x50, в нём вроде используются только 0, 6 и 7 биты? Ссылочкой не поделюсь, т.к. 34 - число, добытое честным экспериментом. Для SPCR=0x50: SPE и MSTR, остальные биты =0, т.е. коэффициент деления 1. Для других коэффициентов, наверное, не 34, поэтому и привёл значение SPCR. AVR Studio это дело симулирует правильно: если между "out SPDR" 34 цикла, передаются байты с промежуткосм в 1 бит. Если меньше - стробы есть, а на линии данных стоит высокий уровеь. Это видел в осциллографе. Частота кварца 20 МГц, МК mega16. Да, разумеется, SPIF взводится по концу передачи байта. Не понимаю, в чём проблема у топикстартера - можно работать в прерывании, можно - опрашивая флаг, как всегда...
|
|
|
|
|
May 22 2008, 17:08
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(Qwertty @ May 20 2008, 18:36)  Я делаю с передачей холостого байта при неактивном /cs. Положил в SPDR и пошел готовить следующие данные. Как обойтись без холостой записи надеюсь подскажет GM Подсказываю, вот так, например, можно делать обмен по спи по прерываниям Код spistc: in temp3,spdr ; st x+,temp3 ; spist1: in tmpsta,SREG ; cpi xl,low(eobuf)+1 ;end of buffer? breq spist2 ;yes, it is ld temp3,x ;send current out spdr,temp3 ;byte spist2: out SREG,tmpsta ; reti Принятые байты замещают в буфере переданные. Инициируется обмен вызовом rcall spist1
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
May 22 2008, 21:53
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(=GM= @ May 22 2008, 21:08)  Подсказываю, вот так, например, можно делать обмен по спи по прерываниям Код spistc: in temp3,spdr ; st x+,temp3 ; spist1: in tmpsta,SREG ; cpi xl,low(eobuf)+1 ;end of buffer? breq spist2 ;yes, it is ld temp3,x ;send current out spdr,temp3 ;byte spist2: out SREG,tmpsta ; reti Принятые байты замещают в буфере переданные. Инициируется обмен вызовом rcall spist1 Повторное использование кода(начало посылки через rcall spist1) выглядит красиво. Но к сожалению на С неприменимо, нужно писать отдельно старт транзакции. Ну и для максимума скорости, ИМХО, такое прерывание не очень, при выборе SPI2X(Focs/2) самым большим тормозом становится время входа/выхода в прерывание
|
|
|
|
|
May 22 2008, 23:09
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(singlskv @ May 22 2008, 20:53)  Повторное использование кода (начало посылки через rcall spist1) выглядит красиво Спасибо, не бог весть что, конечно, но это я сам придумал. Я бы сказал, что это не повторное использование, а именно запуск передачи пакета байт из буфера. Цитата(singlskv @ May 22 2008, 20:53)  Но к сожалению на С неприменимо, нужно писать отдельно старт транзакции На си можно попробовать задействовать оператор свич на две позиции. Цитата(singlskv @ May 22 2008, 20:53)  Ну и для максимума скорости, такое прерывание не очень, при выборе SPI2X(Focs/2) самым большим тормозом становится время входа/выхода в прерывание Да вроде нет, тело прерывания выполняется максимум за 14МЦ + 6-7 на вход, всего 20-21, а на передачу одного байта по спи на максимальной скорости Fclk/2 требуется минимум 17МЦ. И небольшое увеличение времени передачи пакета окупается большим ПЛЮСОМ: положили данные в буфер, толкнули обмен, занялись другими делами, прошло некое время, проверили указатель буфера, забрали принятые данные и всё. А если не требуется приёма данных, то на прерывание потребуется 17-18МЦ. Так что прерывания будут идти практически непрерывно и проверять ничего не надо (:-). Кстати, в вашем фрагменте снимать флаг прерывания в конце транзакции совсем не обязательно.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
May 23 2008, 18:46
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(=GM= @ May 23 2008, 03:09)  Спасибо, не бог весть что, конечно, но это я сам придумал. Я бы сказал, что это не повторное использование, а именно запуск передачи пакета байт из буфера. Ну здесь как раз понравилось именно повторное использование, такой запуск вполне стандартен и понятен, но вот то что это удалось красиво вписать прямо в код прерывания.... Цитата На си можно попробовать задействовать оператор свич на две позиции. к сожалению оверхед который при этом будет на С убивает саму идею. Цитата Да вроде нет, тело прерывания выполняется максимум за 14МЦ + 6-7 на вход, всего 20-21, а на передачу одного байта по спи на максимальной скорости Fclk/2 требуется минимум 17МЦ. Я не очень точно выразился говоря про вход/выход из прерывания, то есть вход/выход это первопричина а в сумме на производительность будет больше всего влиять разница в тактах между: in temp3,spdr ; ...... out spdr,temp3 ;byte для Вашего варианта, при непрерывном трансфере большого куска, на передачу одного байта будет >20-21 тактов Цитата И небольшое увеличение времени передачи пакета окупается большим ПЛЮСОМ: положили данные в буфер, толкнули обмен, занялись другими делами, прошло некое время, проверили указатель буфера, забрали принятые данные и всё. А если не требуется приёма данных, то на прерывание потребуется 17-18МЦ. Так что прерывания будут идти практически непрерывно и проверять ничего не надо (:-). Для "общих" случаев обмена по SPI Ваш вариант видимо практически идеален... Для частных, большой вопрос, тот кусочек кода который я привел был частным случаем, я его привел только для того чтобы показать сколько ТОЧНО длится передача по SPI. Цитата Кстати, в вашем фрагменте снимать флаг прерывания в конце транзакции совсем не обязательно. А вот этот вопрос для меня остается загадкой, дело в том что железки на которой работает этот код я никогда не видел более того, в моем коде такие куски повторяются несколько раз подряд, те байтики шлются непрерывно(4 штуки) ну и первоначально предполагалось войти в прерывание и принять 4 байта, а при этом сброс флага обязателен. Ну и в конечном итоге чтение SPSR заменяет всего-лишь еще один "nop"  Потом концепция чуть изменилась, НО, я на самом деле не знаю нужно ли читать SPSR для запуска новой передачи, даташит на этот счет молчит а натурных испытаний не попалось.... Да, еще добавлю на всякий случай, вход в прерывание для SPI есть суть чтение SPSR с сбросом SPIF.
|
|
|
|
|
May 23 2008, 19:15
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(singlskv @ May 23 2008, 21:46)  Ну здесь как раз понравилось именно повторное использование, такой запуск вполне стандартен и понятен, но вот то что это удалось красиво вписать прямо в код прерывания.... Что делает такой вызов небезопасным. Это хак и ничего красивого в этом нет. разве такой старт был бы чем-то хуже? Код .macro StartSpiTransfer ld temp3,x;send current out spdr,temp3;byte .end macro
|
|
|
|
|
May 23 2008, 19:34
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(defunct @ May 23 2008, 23:15)  Что делает такой вызов небезопасным. Это хак и ничего красивого в этом нет. разве такой старт был бы чем-то хуже? Код .macro StartSpiTransfer ld temp3,x;send current out spdr,temp3;byte .end macro Несомненно это хак, но разьве такие варианты не украшают нашу работу ? Ну а если действительно присмотреться, объясните чем Ваш вариант с макросом надежнее чем просто вызов в нужное место ? повторный вход в любом случае Вы не обеспечили....
|
|
|
|
|
May 24 2008, 00:25
|

Ambidexter
    
Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282

|
Цитата(singlskv @ May 23 2008, 17:46)  Для частных, большой вопрос, тот кусочек кода который я привел был частным случаем, я его привел только для того чтобы показать сколько ТОЧНО длится передача по SPI Ну вот, родил специально для вашего частного случая Код ;Обмен данными по SPI на максимальной скорости Fclk/2 spist1: in temp1,spdr ;принятый байт spistc: out spdr,temp2 ;передадим текущий байт st x+,temp1 ;запомним принятый байт andi xl,0x10 ;коррекция указателя ld temp2,x ;прочитаем nop ;следующий байт nop ;из циклического nop ;буфера nop ;период выдачи nop ;байт на Fclk/2 nop ;должен быть nop ;18 МЦ, необходимо nop ;проверить dec bcounter ;все байты? brne spist1 ;нет ret Здесь две особенности, первая то, что работает точно на Fclk/2, вторая - используется циклический буфер на 16 байт (можно настроить на любой размер кратный степени 2), поэтому не надо задумываться, куда писать или откуда читать. Надо только зарядить bcounter<16 и использовать для чтения из буфера команду ld temp1,-x. Немного непривычно, но когда освоишься, получается компактный код. Можно и нулём останавливать передачу, место есть... Вызов, как предложил defunct Код ld temp2,x rcall spistc В железе не проверял, но вроде должно работать.
--------------------
Делай сразу хорошо, плохо само получится
|
|
|
|
|
Nov 13 2008, 16:47
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Отпишусь тут. Сегодня помучал SPI. Узнал много нового  Не ждать готовности SPI можно. Код void SpiMasterTx(uint8_t data) { do { SPDR = data; } while(SPSR & (1<<WCOL)); } Такая конструкция оказалась вполне работоспособной. То что писал Maik-vs в 4 сообщении этой темы не подтвердилось - данные в SPDR не портятся. Симулятор студии и реальный осциллограф также это подтверждают. Ждать приходится только при чтении: Код uint8_t SpiMasterTxRx(uint8_t data) { do { SPDR = data; } while(SPSR & (1<<WCOL)); while(!(SPSR & (1<<SPIF))); return SPDR; } Оказывается WCOL очень полезный флаг....
|
|
|
|
|
Nov 13 2008, 19:45
|
Местный
  
Группа: Участник
Сообщений: 246
Регистрация: 4-12-06
Пользователь №: 23 101

|
Цитата(Qwertty @ Nov 13 2008, 19:47)  Отпишусь тут. Сегодня помучал SPI. Узнал много нового  Не ждать готовности SPI можно. Код void SpiMasterTx(uint8_t data) { do { SPDR = data; } while(SPSR & (1<<WCOL)); } Такая конструкция оказалась вполне работоспособной. То что писал Maik-vs в 4 сообщении этой темы не подтвердилось - данные в SPDR не портятся. Симулятор студии и реальный осциллограф также это подтверждают. М-да. Оказывается, "while" теперь переводится "не ждать"... Где я писал, что портятся данные в SPDR? Они НЕ ПЕРЕДАЮТСЯ, если запись в SPDR произошла в течение передачи. Это коллизия называется. А Вы фигачите байт в SPDR пока передача не закончится и с нею коллизия стало быть тоже. Хотя в 6-м посте пеклись, как бы "записать SPDR и продолжить заниматься другими делами."
|
|
|
|
|
Nov 13 2008, 21:16
|
Местный
  
Группа: Свой
Сообщений: 408
Регистрация: 21-10-06
Из: Санкт-Петербург
Пользователь №: 21 527

|
Цитата(Maik-vs @ Nov 13 2008, 22:45)  М-да. Оказывается, "while" теперь переводится "не ждать"...  Цель та же - не ждать. Именно это я и получил. Записал в SPDR и пошел гулять, готовить следующие данные. Подготовил быстрее, чем закончилась передача, подожду немного, может пару-тройку тактов. Это лучше, чем например 32. А если данные готовились чуть дольше - вообще ничего не жду. Выигрыш во времени получился вполне ощутимый. И "самосброс" SPIF теперь не помеха. Цитата(Maik-vs @ Nov 13 2008, 22:45)  Где я писал, что портятся данные в SPDR? Они НЕ ПЕРЕДАЮТСЯ, если запись в SPDR произошла в течение передачи. Это коллизия называется. "Писать в SPDR можно через 34 цикла процессора после предыдущей записи (SPCR=0x50). Раньше - синхроимпульсы будут, а данные - нет." Я вот про это. Запись в SPDR во время передачи вызывает только один эффект - взвод WCOL. На передаваемые данные никак не влияет. Когда передача закончится, запись в SPDR вызовет начало новой передачи совершенно обычным способом.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|