|
ATmega8 SPI ADS1242, Работа с SPI |
|
|
|
Jan 21 2008, 13:04
|
Частый гость
 
Группа: Новичок
Сообщений: 83
Регистрация: 2-02-06
Пользователь №: 13 912

|
Пытаюсь наладить связь ATmega8 (7.3728 MHz) с ADS1242 (2.4576 MHz) по SPI (WinAVR). Вопрос : как узнать что пришли данные от ADS1242. Инициализирую SPI ATmega8 как мастер: void SPI_MasterInit(void) { // MOSI,SCK,SS на выход, MISO на вход DDRB=0x2E; // Включение SPI, мастер, частота /32 SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1); SPSR = (1<<SPI2X); PORTB|=(1<<2); void SPI_Transmit(unsigned char cData) { /* Запуск передачи данных */ SPDR = cData; /* Ожидание завершения передачи данных */ while(!(SPSR & (1<<SPIF))); В документации на ADS1242 написано, что для чтения данных из регистра нужно послать команду Encoding: 0001 rrrr xxxx nnnn (rrrr - номер первого регистра для чтения, nnnn читать колличество регистров после первого ) Читаю так: PORTB&=(~(1<<2));//выбор чипа SS=0; SPI_Transmit(0x10);//читать регистр с номером 0x00 SPI_Transmit(0x01);// читать 2 регистра начиная с первого _delay_us (25);// задержка по даташиту мин. 50 Tosc(2.4576) USART_Transmit(SPDR);//пытаюсь прочитать присланные данные PORTB|=(1<<2);//SS выставляю в 1 для сброса читаються то 0x00 то 0xFF Как понять что данные о первом регистре уже пришли их нада прочитать, ну а затем соответственно и данные от второго регистра Подскажите что не так
Сообщение отредактировал URANst - Jan 21 2008, 13:22
|
|
|
|
|
Jan 21 2008, 15:31
|
Частый гость
 
Группа: Новичок
Сообщений: 170
Регистрация: 26-05-05
Из: Москва
Пользователь №: 5 405

|
Цитата(URANst @ Jan 21 2008, 16:04)  ... PORTB&=(~(1<<2));//выбор чипа SS=0; SPI_Transmit(0x10);//читать регистр с номером 0x00 SPI_Transmit(0x01);// читать 2 регистра начиная с первого _delay_us (25);// задержка по даташиту мин. 50 Tosc(2.4576) USART_Transmit(SPDR);//пытаюсь прочитать присланные данные PORTB|=(1<<2);//SS выставляю в 1 для сброса читаються то 0x00 то 0xFF Как понять ... SPI ведь у нас как работает? Для того, чтобы прочитать, нужно послать  Ну, в общем, наиболее частом случае. Если хотите прочитать 2 регистра, то читаем доку, стр.19, и обращаем внимание на Data Transfer Sequence. Попробуйте вместо выделенной строки вставить что-нибудь вроде: Код SPI_Transmit(0xAA); //На самом деле, неважно что посылать USART_Transmit(SPDR); //Посылаем данные из первого регистра SPI_Transmit(0xAA); //Тут тоже неважно что посылать USART_Transmit(SPDR); //Посылаем данные из второго регистра Удачи!
|
|
|
|
|
Jan 21 2008, 17:29
|
Частый гость
 
Группа: Новичок
Сообщений: 83
Регистрация: 2-02-06
Пользователь №: 13 912

|
Цитата SPI_Transmit(0xAA); //На самом деле, неважно что посылатьUSART_Transmit(SPDR); //Посылаем данные из первого регистраSPI_Transmit(0xAA); //Тут тоже неважно что посылатьUSART_Transmit(SPDR); //Посылаем данные из второго регистра Что то я вас не пойму : что значит неважно что посылать ? Там помойему четко написано : для того что бы прочитать регистр нужно записать 0001 - номер регистра(4 бита) - количество регистров(8 бит): всего 2 байта. Может вы не совсем поняли USART_Transmit(SPDR); читает принятые от АЦП данные и посылает по RS232. Так вот я спрашивал как мне узнать что из 2-ух байт, которые должны прити, сейчас пришел первый из них, а потом второй . Я имею ввиду может SPIF какой устанавливается или еще что. И еще как поступать если програмирую ATmega8 по SPI. Это оказывает какое влияние на АЦП и если да то что делать. Пока при попытке прочитать шлю 00010000 00000000 (прочитать значение регистра с номером 0x00) принимаю строго 0xFF. Что за ерунда кто скажет.
|
|
|
|
|
Jan 21 2008, 18:27
|

Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317

|
2 URANstЯ полагаю, что должно быть так: Код #include <avr\io.h>
#define SPI_PORT PORTB #define SPI_DDR DDRB
#define MOSI_P PB3 #define MISO_P PB4 #define SCK_P PB5 #define SS_P PB2
// При этом, SS_P подключен к чип-селектку ведеомого устройства
// Эта функция сдвигает по SPI один байт, и возвращает байт, // прочитанный со слейва uint8_t spi_shift_byte(uint8_t data) { SPI_PORT &= ~(1 << SS_P); SPDR = data; while(!(SPSR & (1 << SPIF))); SPI_PORT |= (1 << SS_P); return SPDR; }
int main(void) {
uint8_t data[3]; // Данные прочитанные с АЦП ////////////////////////////////////////////////////////////////////////// // Настройки SPI SPI_DDR = (1 << MOSI_P)|(1 << SCK_P)|(1 << SS_P); SPI_PORT = (1 << SS_P); // Чипселект в еденице - приемник неактивен SPCR = (1 << SPE)|(1 << MSTR)|(1 << SPR1); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Далее, судя по документации, делать нужно так: spi_shift_byte(0x01); // Код команды spi_shift_byte(0); // Байт параметров (как я понял). Оставляем пустым // Далее читаем три байта ригистра АЦП: data[2] = spi_shift_byte(0); // Старший байт data[1] = spi_shift_byte(0); // Средний байт data[2] = spi_shift_byte(0); // Младший байт }
|
|
|
|
|
Jan 21 2008, 20:11
|

Местный
  
Группа: Свой
Сообщений: 222
Регистрация: 9-06-07
Пользователь №: 28 317

|
2 URANstВот я попытался изобразить функции чтения/записи группы регистров. Плюс, некоторые изменения вне в функцию spi_shift_byte. Код #include <avr\io.h> #include <util/delay.h>
#define SPI_PORT PORTB #define SPI_DDR DDRB
#define MOSI_P PB3 #define MISO_P PB4 #define SCK_P PB5 #define SS_P PB2
#define SELECT() SPI_PORT &= ~(1 << SS_P) #define DESELECT() SPI_PORT |= (1 << SS_P)
// При этом, SS_P подключен к чип-селектку ведеомого устройства
// Эта функция сдвигает по SPI один байт, и возвращает байт, // прочитанный со слейва uint8_t spi_shift_byte(uint8_t data) { SPDR = data; while(!(SPSR & (1 << SPIF))); return SPDR; }
adc_read_registers(uint8_t start_address, uint8_t count, uint8_t* buffer) { start_address &= 0x0F; count &= 0x0F;
SELECT(); spi_shift_byte(0x08 | (start_address)); // 0001 rrrr spi_shift_byte(count - 1); // xxxx nnnn, почему "минус 1" - написано в документации // Задержку, я думаю подберете сами... _delay_us(25); for (;count; count--, buffer++) *buffer = spi_shift_byte(0); // Читаем count регистров в массив buffer
DESELECT(); }
adc_write_registers(uint8_t start_address, uint8_t count, uint8_t* buffer) { start_address &= 0x0F; count &= 0x0F; SELECT(); spi_shift_byte(0x50 | (start_address)); // 0101 rrrr spi_shift_byte(count - 1); // xxxx nnn, почему "минус 1" - написано в документации for (;count; count--, buffer++) spi_shift_byte(*buffer); // Передаем count значений из массива buffer DESELECT(); }
int main(void) { ////////////////////////////////////////////////////////////////////////// // Настройки SPI SPI_DDR = (1 << MOSI_P)|(1 << SCK_P)|(1 << SS_P); SPI_PORT = (1 << SS_P); // Чипселект в еденице - приемник неактивен SPCR = (1 << SPE)|(1 << MSTR)|(1 << SPR1); // F_CPU/128 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
uint8_t buffer[2] = {0xAA, 0xBB}; // Значения от балды... // Пишем два регистра и buffer, начиная с решистра №1 adc_write_registers(1, 2, buffer); // Читаем 2 регситра в buffer, начиная с регистра №5 adc_read_registers(5,2,buffer); }
|
|
|
|
|
Jan 22 2008, 11:16
|
Частый гость
 
Группа: Новичок
Сообщений: 170
Регистрация: 26-05-05
Из: Москва
Пользователь №: 5 405

|
Цитата(URANst @ Jan 22 2008, 11:36)  ... После этого принимаю постоянно разные значения UART налажен нармально - до этого тестился. CPU_cloc 7.3728 baund rate 9600 UBBR 47
Посоветуйте что нить, а то уже сил нет ! Во-первых, научитесь при создании сообщения вставлять исходный текст с помощью соответствующей кнопки (#) - она ведь для этого и создана. Во-вторых, приведите полный исходник. В данном случае не понятно, что делается в main(). В-третьих, убедитесь сами (а не предлагайте другим считать делители) раз и навсегда, что данные по UART'у передаются корректно: киньте посылку из разных байт и проверьте её приём на другом конце (можете дополнительно сделать это в цикле). Ну и в-четвёртых, а какие собственно разные данные приходят от ADS1242? P.S. Для корректности ставьте DESELECT по окончании работы с SPI.
|
|
|
|
|
Jan 22 2008, 13:28
|
Частый гость
 
Группа: Новичок
Сообщений: 83
Регистрация: 2-02-06
Пользователь №: 13 912

|
Выкладываю полный текст программы. После прихода комманды 0x32 и еще чего нибудь нужно выполнить запись и чтение из АЦП. Подозрение что не работает задержка. Код #include <avr/io.h> #include <avr/interrupt.h> #include <avr/delay.h>
#define UBRRVAL 47
#define SPI_PORT PORTB #define SPI_DDR DDRB
#define MOSI_P PB3 #define MISO_P PB4 #define SCK_P PB5 #define SS_P PB2
#define SELECT() SPI_PORT &= ~(1 << SS_P) #define DESELECT() SPI_PORT |= (1 << SS_P)
unsigned char command,statbuf,buf;
[code]void USART_init(void) { //Set baud rate Код [/code] UBRRL=UBRRVAL; //low byte UBRRH=(UBRRVAL>>8); //high byte //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size UCSRC=(1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(0<<USBS)|(0<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0); //Enable Transmitter and Receiver and Interrupt on receive complete UCSRB=(1<<RXEN)|(1<<TXEN)|(1<<RXCIE); } void USART_Transmit(unsigned char data) {
while ( !( UCSRA & (1<<UDRE)) ) {}; UDR = data; }
void SPI_init(void) {
SPI_DDR = (1 << MOSI_P)|(1 << SCK_P)|(1 << SS_P); SPI_PORT = (1 << SS_P); // Чипселект в еденице - приемник неактивен SPCR = (1 << SPE)|(1 << MSTR)|(1 << SPR1)|(1 << SPR0); // F_CPU/128 } unsigned char spi_shift_byte(unsigned char data) { SPDR = data; while(!(SPSR & (1 << SPIF))); return SPDR; }
unsigned char RREG(unsigned char start_address) { unsigned char buffer; SELECT(); spi_shift_byte(0x10 | (start_address)); // 0001 rrrr spi_shift_byte(0x01); // xxxx nnnn, почему "минус 1" - написано в документации _delay_loop_2(250); buffer = spi_shift_byte(0xAA); // Читаем count регистров в массив buffer DESELECT(); return buffer; }
void WREG(unsigned char address, unsigned char value) { SELECT(); spi_shift_byte(0x50 | (address)); // 0101 rrrr spi_shift_byte(0x00); // xxxx nnn, почему "минус 1" - написано в документации spi_shift_byte(value); // Передаем count значений из массива buffer DESELECT(); }
ISR (USART_RXC_vect) { while ( !(UCSRA & (1<<RXC)) ); buf=UDR; statbuf=0x01; }
void processing (void) {
unsigned char SPI_buf; if ((statbuf==0x01) && (command==0x00)) { command=buf; buf=0x00; statbuf=0x00; } if (command!=0x00) { switch (command) { case 0x31: { USART_Transmit(0x01); command=0x00; break; } case 0x32: { if (statbuf==0x01) { USART_Transmit(0x02); SELECT(); SPDR = 0x51; while(!(SPSR & (1 << SPIF))); SPDR = 0x01; while(!(SPSR & (1 << SPIF))); SPDR = 0x05; while(!(SPSR & (1 << SPIF))); SPDR = 0x07; while(!(SPSR & (1 << SPIF))); DESELECT(); _delay_ms(10000); SELECT(); SPDR = 0x11; while(!(SPSR & (1 << SPIF))); SPDR = 0x01; while(!(SPSR & (1 << SPIF))); _delay_ms(25); SPDR = 0xAB; while(!(SPSR & (1 << SPIF))); SPI_buf=SPDR; USART_Transmit(SPI_buf); SPDR = 0xAC; while(!(SPSR & (1 << SPIF))); SPI_buf=SPDR; USART_Transmit(SPI_buf); DESELECT(); buf=0x00; statbuf=0x00; command=0x00; } break; } default: { command=0x00; break; } } } }
int main (void) {
USART_init(); SPI_init(); sei(); while (1) { processing (); } }
|
|
|
|
|
Jan 22 2008, 15:30
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(Aesthete Animus @ Jan 22 2008, 18:03)  Кстати, очень может быть - у меня вечно с задержкой _delay_us/_delay_ms были разные проблемы. Лучше пользоваться _delay_loop_2 и вручную рассчитывать задержку. Если у Вас были проблеммы с , то это не причина рекомендовать людям ими не пользоваться. 2 URANst: 1. Совпадат ли значения макроса F_CPU в makefile с реальной частотой контроллера? 2. Какой уровень оптимизации вы используете. Для корректного использования макросов _delay_us/_delay_ms должна быть не менее -01. (Перед включением оптимизации не забудте что в стандарте языка С есть слово 'volatile'). 3. В описании функци _delay_ms обратите внимание на предложение: The maximal possible delay is 262.14 ms / F_CPU in MHz. Анатолий.
Сообщение отредактировал aesok - Jan 22 2008, 16:16
|
|
|
|
|
Jan 22 2008, 19:06
|
Частый гость
 
Группа: Новичок
Сообщений: 83
Регистрация: 2-02-06
Пользователь №: 13 912

|
Уважаемый proba, что вы имели ввиду под Код delay !!! a = 6; while (a--); // @ 4MHz Код delay !!! a= 60; While (a--); // @4MHz Я так понимаю что Код a = 6 и Код a= 60 - это задержка в периодах, тока подскажите в периодах чего ? тактовой ATmega8 (7.3728 MHz) или ADS1242 (2.4576 MHz) или частоты SPI (7.3728 MHz/128). proba может вы мне вышлите какую нить вашу схемку с ADS1242 и файл прошивки (.с) (очень интересно посмотреть) mail:URANstin@mail.ruА зачем задержка Код delay !!! a = 6; while (a--); // @ 4MHz , в даташите вроде ненаписано что такую нада использовать. Подскажите как описать задержку. Я делаю так: Код #include <avr/delay.h> или #include <util/delay.h> _delay_loop_2(100) ? - 100 в каких единицах ? _delay_us(50); Похоже что не работает. aesok ! Код 1. Совпадат ли значения макроса F_CPU в makefile с реальной частотой контроллера? да Код 2. Какой уровень оптимизации вы используете. s Код 3. В описании функци _delay_ms обратите внимание на предложение: The maximal possible delay is 262.14 ms / F_CPU in MHz. то есть у меня макс 262,14/7,3728=35 ms, а если мне нужна задержка в 1 сек так что цикл лепить. Как делаете вы задержки. Извините за ламерские вопросы с WinAVR тока начал работать, сразу понравильсь а ща вот так  ) И еще подскажите какой WinAVR вы пользуетесь, и где ее можно скачать ? мож у меня версия кривая.
|
|
|
|
|
Jan 22 2008, 19:19
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Код #include <avr/delay.h> или #include <util/delay.h> _delay_loop_2(100) ? - 100 в каких единицах ? в циклах контроллера. Цитата(URANst @ Jan 22 2008, 22:06)  Код 3. В описании функци _delay_ms обратите внимание на предложение: The maximal possible delay is 262.14 ms / F_CPU in MHz. то есть у меня макс 262,14/7,3728=35 ms, а если мне нужна задержка в 1 сек так что цикл лепить. Как делаете вы задержки. Если у вас старая версия WinAVR, то да лепить циклы, или дополнительную функцию задержки. Если WinAVR 20071221 то возможно нет, недавно меняли макрос _delay_ms, и возможно он сам вставит цикл. Посмотрите описание или код _delay_ms в файле util/delay.h Цитата И еще подскажите какой WinAVR вы пользуетесь, и где ее можно скачать ? мож у меня версия кривая. WinAVRАнатолий.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|