|
Не работает SPI., на at91sam7x256 |
|
|
|
Oct 23 2008, 15:51
|
Местный
  
Группа: Свой
Сообщений: 238
Регистрация: 11-08-05
Пользователь №: 7 557

|
Ситуация такова. К AT91SAM7X256 подключены два датчика. Акселерометр ADIS16201 и гироскоп ADIS16255. Акселерометр 3-х вольтовый(5 вольт выдерживает, раньше к авр 5вольтовому был подключен), гироскоп 5-вольтовый(но 3.3В понимает) ну и SAM7X 3-х вольтовый. Подтяжки аппаратные есть только на чип селектах датчиков. чип селект акселерометра подтянут к 3.3В, чип селект гироскопа к 5В. SPCK,MOSI,MISO никаких подтяжек не имеют. при работе на всех ножках (CS,SPCK,MOSI,MISO) напряжение 3.3В. кабель длинной ~40см ну и плюс какое-то(~10см) расстояние на тоненькие(0.15мм) дорожки на самой плате. Это, что касается железной части SPI. Датчики подключены к SPI0. Чип селекты NPCS0..3 не используются! В качестве CS используются две ножки PB0 и PB1. Дергаются программно. Сам интерфейс вроде запускается, клок идет. какие то данные на MISO и MOSI есть. но читается фигня! Привожу код работы с SPI0. Посмотри пожалуйста, не могу понять где ошибка. Датчики общаются по 16бит SPI. Чтобы с них что-то прочитать нужно сначала отправить адрес регистра который нужно прочитать, датчик вернет результат предыдущего запроса. потом еще раз отправить что-нибудь и датчик тока датчик вернет то, что мы просили у него в первый раз. сама логика работы с акселерометром прописана на стр15 http://www.analog.com/static/imported-file...s/ADIS16201.pdfВыкладываю свой код. Здесь я пытаюсь прочитать по адресу 0x02 напряжение питания акселерометра. он мне возвращает 16 бит, из них 12 само напряжение в binary format.далее оно умножается на 1.22мВ и получается напр питания. у меня по этому коду, читается через раз. иногда 0, иногда ерунда какая-то. показания зависят от положения датчика! если его крутить то данные меняются, если пытаться читать из других регистров то результат примерно такой же. В общем я думаю ошибка где то в самом коде работы с SPI.раньше это пара датчиков отлично работала с 5В авр. Код #define SPI_PCS(npcs) ((~(1 << npcs) & 0xF) << 16) #define SCBR(_scbr) (_scbr<<8)
//функция инициализации SPI void SPI0_Init(void); //отправка 16 бит данных по SPI void SPI0_Send_data(unsigned short data); //функция принимает 16 бит данных по SPI unsigned short SPI0_Get_data(void); //Включение чип селекта акселлерометра PB0=0, //выключение чип селекта гироскопа PB1=1 void ACCE_ON(void); //Включение чип селекта гироскопа PB1=0, //выключение чип селекта акселлерометра PB0=0 void GYRO_ON(void); //Выключение и гироскопа и акселлерометра PB0=1,PB1=1; void SENSORS_OFF(void);
int main() { //Умножаем 12бит данных из регистра POWER SUPPLY на k = 1.22mV и получаем //напряжение питания акселлерометра const float k = 1.22; //адрес по которому читаем данные unsigned short addr = 0x02; unsigned short dummy = 0; unsigned short result; float POWER_SUPPLY[100]=0; //Инициализируем SPI SPI0_Init(); //Будем читать с акселлерометра регистр POWER SUPPLY по адресу 0x02. while(1) { //Включаем акселлерометр ACCE_ON(); //Отправляем в акселлерометр адрес регистра который надо прочитать SPI0_Send_data(addr); //Читаем результат основанный на предыдущей команде и игнорируем его dummy = SPI0_Get_data(); //После того как отправили адрес по которому хотим прочитать данные. нужно //совершить вторую итерацию чтения, по любому адресу. и акселлерометр выдаст нам //данные запрошенные в первой итерации(т.е по адресу addr) //Вторая итерация чтения //Передергиваем чип селект для начала второй итерации чтения //Выключаем датчик SENSORS_OFF(); //Включаем чип селект акселлерометра ACCE_ON(); //Отправляем в акселлерометр любое число. не имеет значения какое SPI0_Send_data(addr); //В ответ получаем то что лежит по адресу который отправили в первой итерации //чтения result= SPI0_Get_data(); //Выключаем акселлерометр SENSORS_OFF(); //Значащие данные в result - 12бит. затиравем остальное нулями result &= 0x0FFF; //тут получаем ответ POWER_SUPPLY = result *k; } return 0; }
void SPI0_Init(void) { //--------Настройка чип селектов акселлерометра и гироскопа-----------------// //аппаратные чип селекты не используются для управления гироскопом и //акселлерометром. для активация/деактивации датчиков используются линии //PIO. PB0-чип селект акселлерометра. PB1-чип селект гироскопа. //Включение тактирования PIOB AT91C_BASE_PMC->PMC_PCER |= 1 << AT91C_ID_PIOB; //Инициализация PB0 и PB1 //включение PB0,PB1 как линии ввода,вывода AT91C_BASE_PIOB->PIO_PER |= AT91C_PIO_PB0 | AT91C_PIO_PB1; //отключение подтягивающих к плюсу питания резисторов AT91C_BASE_PIOB->PIO_PPUDR |= AT91C_PIO_PB0 | AT91C_PIO_PB1; //настраиваем PB0 и PB1 на выход AT91C_BASE_PIOB->PIO_OER |= AT91C_PIO_PB0 | AT91C_PIO_PB1; //разрешаем синхронный вывод данных на PB0 и PB1 AT91C_BASE_PIOB->PIO_OWER |= AT91C_PIO_PB0 | AT91C_PIO_PB1; //выключаем оба датчика. PB0=1 и PB1=1 SENSORS_OFF(); //--------------------------------------------------------------------------// //----------------------Настройка SPI0--------------------------------------// //Отключаем PIO от управления MOSI,SCK,MISO,NPCS0.NPCS0-не используется! AT91C_BASE_PIOA->PIO_PDR |= AT91C_PA12_SPI0_NPCS0 | AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //Отключаем подтяжки на линиях MISO,MOSI,SPCK AT91C_BASE_PIOA->PIO_PPUDR |= AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //конфигурируем MOSI,MISO,SPCK,NPCS0 как перифирию A AT91C_BASE_PIOA->PIO_ASR |= AT91C_PA12_SPI0_NPCS0 | AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //Включаем тактирование SPI0 AT91C_BASE_PMC->PMC_PCER |= 1 << AT91C_ID_SPI0; //отключение SPI и сброс SPI AT91C_BASE_SPI0->SPI_CR |= AT91C_SPI_SPIDIS | AT91C_SPI_SWRST; //SPI в режиме Master, фиксированная перефирия,тактирование от MCK AT91C_BASE_SPI0->SPI_MR |= AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | SPI_PCS(0); //CPOL=1,PHASE=1,16 битный режим, SPCKHMhz/255 = 188,2Khz AT91C_BASE_SPI0->SPI_CSR[0] |= AT91C_SPI_CPOL | AT91C_SPI_NCPHA | AT91C_SPI_BITS_16 | SCBR(0xFF); //SPI enable AT91C_BASE_SPI0->SPI_CR |= AT91C_SPI_SPIEN; //--------------------------------------------------------------------------// }
void SPI0_Send_data(unsigned short data) { //Ждем когда TDRE и внутреннее сдвигающие устройство станут пустыми while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TXEMPTY) == 0); //копируем данные в регистр передачи TDR AT91C_BASE_SPI0->SPI_TDR = data | SPI_PCS(0) | AT91C_SPI_LASTXFER; //Ждем пока данные скопируются в сдвигающий реситр while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_TDRE) == 0); }
unsigned short SPI0_Get_data(void) { //читаем данные while ((AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_RDRF) == 0); return AT91C_BASE_SPI0->SPI_RDR & 0xFFFF; }
//Включаем акселлерометр PB0=0, PB1=1 void ACCE_ON(void) { AT91C_BASE_PIOB->PIO_ODSR = (AT91C_PIO_PB1 & ~AT91C_PIO_PB0); }
//Включаем гироскоп PB0=1, PB1=0 void GYRO_ON(void) { AT91C_BASE_PIOB->PIO_ODSR = (AT91C_PIO_PB0 & ~AT91C_PIO_PB1); }
void SENSORS_OFF(void) { AT91C_BASE_PIOB->PIO_ODSR |= AT91C_PIO_PB0 | AT91C_PIO_PB1; }
|
|
|
|
|
 |
Ответов
|
Oct 24 2008, 13:27
|
Местный
  
Группа: Свой
Сообщений: 238
Регистрация: 11-08-05
Пользователь №: 7 557

|
Подправил немного код и железо. все равно не работает зараза! пятый день уже сижу Сделал следующее. выпаял подтягивающий к 5В резистор на линии CS гироскопа. включил внутренние подтягивающие резисторы на SPCK,MISO,MOSI, CS гироскопа. Исправил все места где читались регистры только для записи. исправил процедуру передачи данных по SPI.сбросил NCPHA. Все. больше не знаю, что делать. ставлю брэйкпоинт на while(1), смотрю, что лежит в POWER_SUPPLY. при первом запуске там все 0. жму ресет, запускаю еще раз, там в основном число 90мв, иногда 246мв,иногда 0. Код #include <global.h>
#define SPI_PCS(npcs) ((~(1 << npcs) & 0xF) << 16) #define SCBR(_scbr) (_scbr<<8)
//функция иннициализация SPI void SPI0_Init(void); //Фунцкия передачи данных по SPI unsigned int SPI0_trans(unsigned int data); //Включение чип селекта акселлерометра PB0=0, //выключение чип селекта гироскопа PB1=1 void ACCE_ON(void); //Включение чип селекта гироскопа PB1=0, //выключение чип селекта акселлерометра PB0=0 void GYRO_ON(void); //Выключение и гироскопа и акселлерометра PB0=1,PB1=1; void SENSORS_OFF(void);
int main() { //Умножаем 12бит данных из регистра POWER SUPPLY на 1.22mV и получаем //напряжение питания акселлерометра const float k = 1.22; unsigned int addr = 0x0200; unsigned int dummy = 0; unsigned int result; unsigned int i=0; float POWER_SUPPLY[100]=0; //Инициализируем SPI SPI0_Init(); //Будем читать с акселлерометра регистр POWER SUPPLY по адресу 0x02. for(i=0;i<100;i++) { //Включаем акселлерометр ACCE_ON(); //Отправляем в акселлерометр адрес регистра который надо прочитать dummy = SPI0_trans(addr); //После того как отправили адрес по которому хотим прочитать данные. нужно //совершить вторую итерацию чтения, по любому адресу. и акселлерометр выдаст нам //данные запрошенные в первой итерации(т.е по адресу addr) //Вторая итерация чтения //Передергиваем чип селект для начала второй итерации чтения //Выключаем датчик SENSORS_OFF(); //Включаем чип селект акселлерометра ACCE_ON(); //Отправляем в акселлерометр любое число. не имеет значения какое //В ответ получаем то что лежит по адресу который отправили в первой итерации //чтения result = SPI0_trans(addr); //Выключаем акселлерометр SENSORS_OFF(); //Значащие данные в result - 12бит. затиравем остальное нулями result &= 0xFFF; POWER_SUPPLY[i] = result *k; } while(1); return 0; }
void SPI0_Init(void) { //аппаратные чип селекты не используются для управления гироскопом и //акселлерометром. для активация/деактивации датчиков используются линии //PIO. PB0-чип селект акселлерометра. PB1-чип селект гироскопа. //Включение тактирования PIOB и SPI0 AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOB) | (1 << AT91C_ID_SPI0); //Инициализация PB0 и PB1 //включение PB0,PB1 как линии ввода,вывода AT91C_BASE_PIOB->PIO_PER = AT91C_PIO_PB0 | AT91C_PIO_PB1; //отключение подтягивающих к плюсу питания резисторов на PB0,SPCK //MOSI,MISO. на PB0-есть аппартная подтяжка 4.7K к 3.3В. на PB1 оставляем //включенной встроенную в МК подтяжку к 3.3В. SPCK,MOSI,MISO - без подтяжек //AT91C_BASE_PIOB->PIO_PPUDR = AT91C_PIO_PB0 | AT91C_PA16_SPI0_MISO | // AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //настраиваем PB0 и PB1 на выход AT91C_BASE_PIOB->PIO_OER = AT91C_PIO_PB0 | AT91C_PIO_PB1; //разрешаем синхронный вывод данных на PB0 и PB1 AT91C_BASE_PIOB->PIO_OWER = AT91C_PIO_PB0 | AT91C_PIO_PB1; //выключаем оба датчика. PB0=1 и PB1=1 SENSORS_OFF(); //Отключаем PIO от управления MOSI,SCK,MISO,NPCS0.NPCS0-не используется! AT91C_BASE_PIOA->PIO_PDR = AT91C_PA12_SPI0_NPCS0 | AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //конфигурируем MOSI,MISO,SPCK,NPCS0 как перифирию A AT91C_BASE_PIOA->PIO_ASR = AT91C_PA12_SPI0_NPCS0 | AT91C_PA16_SPI0_MISO | AT91C_PA17_SPI0_MOSI | AT91C_PA18_SPI0_SPCK; //отключение SPI и сброс SPI AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIDIS | AT91C_SPI_SWRST; //SPI в режиме Master, фиксированная перефирия,тактирование от MCK AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | SPI_PCS(0); //CPOL=1,16 битный режим, SPCKHMhz/255 = 188,2Khz AT91C_BASE_SPI0->SPI_CSR[0] = AT91C_SPI_CPOL | AT91C_SPI_BITS_16 | SCBR(0xFF); //SPI enable AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN; //--------------------------------------------------------------------------// }
unsigned int SPI0_trans(unsigned int data) { AT91C_BASE_SPI0->SPI_TDR = data; while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_RDRF)); return (AT91C_BASE_SPI0->SPI_RDR); }
//Включаем акселлерометр PB0=0, PB1=1 void ACCE_ON(void) { AT91C_BASE_PIOB->PIO_ODSR = AT91C_PIO_PB1; }
//Включаем гироскоп PB0=1, PB1=0 void GYRO_ON(void) { AT91C_BASE_PIOB->PIO_ODSR = AT91C_PIO_PB0; } //PB0=1,PB1=0 void SENSORS_OFF(void) { AT91C_BASE_PIOB->PIO_ODSR = AT91C_PIO_PB0 | AT91C_PIO_PB1; }
|
|
|
|
|
Oct 25 2008, 07:24
|
Местный
  
Группа: Свой
Сообщений: 238
Регистрация: 11-08-05
Пользователь №: 7 557

|
Заработало!  Проблема была в том, что пауза между двумя передергиваниями чип селекта отсутствовала. Надо было доку на датчики читать, а я на проц грешил. такой код работает. Код for(i=0;i<100;i++) { //ждем j=0; for(j=0;j<800;j++); ACCE_ON(); dummy = SPI0_trans(addr); SENSORS_OFF(); //ждем опять j=0; for(j=0;j<800;j++); ACCE_ON(); result = SPI0_trans(addr); SENSORS_OFF(); result &= 0xFFF; POWER_SUPPLY[i] = result *k; } while(1); всем спасибо за помощь. aaarrr Пока писал этот код возникли четыре вопроса. 1) Есть регистры только для записи. Из них читать нельзя. Допустим я хочу в одном месте включить тактирование PIOB. я пишу Код AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_PIOB) потом, в другом месте программы, я хочу включить тактирование SPI я пишу Код AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_SPI0); тем самым затирая бит (1 << AT91C_ID_PIOB) и выключая тактирование PIOB. писать так Код AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_SPI0); чтобы не трогать ранее записанное в PCER значение я не могу. Вопрос: Как правильно писать в такие регистры(только для записи), чтобы не затирать ранее записанные в них значения? 2) Код AT91C_BASE_PIOB->PIO_ODSR = (1UL * AT91C_PIO_PB1) | (0UL * AT91C_PIO_PB0); каков тайный смысл данного кода?я так понял что 1UL и 0UL- это unsigned long единица и ноль. а (1UL * AT91C_PIO_PB1) | (0UL * AT91C_PIO_PB0) = AT91C_PIO_PB1. в чем смысл этой записи? 3)Кто каким образом делаем задержки в программах? в авр была функция __delay_cycles(). и с помощью нее можно было делать паузы. кто как в арм делает? 4)Если мне надо работать с данными от байта до двух. какой тип данных под них лучше резервировать? я так думаю, что если памяти не жалко и нужно быстродействие то лучше все переменные хранить в int. процессор то 32 бита(режим АРМ). а если памяти жалко и скорость не важна то лучше распихивать все по char или short в зависимости от велечины переменной. правильно я думаю?
|
|
|
|
|
Oct 25 2008, 10:36
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(Dars @ Oct 25 2008, 10:24)  2) Код AT91C_BASE_PIOB->PIO_ODSR = (1UL * AT91C_PIO_PB1) | (0UL * AT91C_PIO_PB0); каков тайный смысл данного кода?я так понял что 1UL и 0UL- это unsigned long единица и ноль. а (1UL * AT91C_PIO_PB1) | (0UL * AT91C_PIO_PB0) = AT91C_PIO_PB1. в чем смысл этой записи? Очень простой. Через месяц-полгода глядя в свои же исходники, в которых написано AT91C_BASE_PIOB->PIO_ODSR = AT91C_PIO_PB1; вы будете думать "А ведь микросхема висит на PB1 и PB0, я тут забыл PB0! Потом посмотрите в схему и поймете, что в PB0 здесь надо записать ноль и ошибки нет. А глядя в запись (1UL * AT91C_PIO_PB1) | (0UL * AT91C_PIO_PB0) сразу видно: в PB1 записана 1, в PB0 записан 0. Еще один плюс такой записи: надо внести изменение - меняем одну цифру. В вашем же случае пришлось бы стирать или вписывать "AT91C_PIO_PBx". Цитата(Dars @ Oct 25 2008, 10:24)  3)Кто каким образом делаем задержки в программах? в авр была функция __delay_cycles(). и с помощью нее можно было делать паузы. кто как в арм делает? В ARM время исполнения инструкции зависит от того, откуда выполняется код (ОЗУ, флеш, кэш), от настроек контроллера флеш и других факторов. Поэтому невозможно реализовать __delay_cycles(). Если нужна точная задержка - используйте таймер. Если точность не важна - for(volatile int i = 0; i < TIME; ++i); Цитата(Dars @ Oct 25 2008, 10:24)  4)Если мне надо работать с данными от байта до двух. какой тип данных под них лучше резервировать? я так думаю, что если памяти не жалко и нужно быстродействие то лучше все переменные хранить в int. процессор то 32 бита(режим АРМ). а если памяти жалко и скорость не важна то лучше распихивать все по char или short в зависимости от велечины переменной. правильно я думаю? В принципе, да. А еще лучше использовать типы из stdint.h, которые добавляют портируемости.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
Сообщений в этой теме
Dars Не работает SPI. Oct 23 2008, 15:51 aaarrr Цитата(Dars @ Oct 23 2008, 19:51) Код //... Oct 23 2008, 17:57 Сергей Борщ Цитата(aaarrr @ Oct 23 2008, 20:57) Зачем... Oct 23 2008, 18:39   Alexandro Цитата(Dars @ Oct 25 2008, 10:24) Вопрос:... Oct 25 2008, 09:13 aaarrr Хорошо, а что говорит осциллограф? И Вы не пробова... Oct 24 2008, 14:08 Dars Цитата(aaarrr @ Oct 24 2008, 18:08) Хорош... Oct 24 2008, 15:22  aaarrr Цитата(Dars @ Oct 24 2008, 19:22) что зна... Oct 24 2008, 15:31   Dars Цитата(aaarrr @ Oct 24 2008, 19:31) Наско... Oct 24 2008, 15:37
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|