Полная версия этой страницы:
SPI и Atmega128A
ADEPTPS
Dec 14 2011, 08:03
Проблема:
не получается принять данные.
В даташите есть функция настройки SPI на мастер: // в ней есль только отправка данных, пытаюсь принимать данные с SPDR, но считываю лишь то что отсылаю!
Код
void SPI_MasterInit()
{
DDR_SPI = (1<<DD_MOSI)|(1<<DD_SCK);//настраиваем на выход
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);//вкл SPI, ведущий, частота fck/16
}
//функция передачи байта
void SPI_MasterTransmit(char cData)
{
SPDR = cData;//начинаем передачу
while(!(SPSR & (1<<SPIF)));//ждем пока передача завершится
}
hd44780
Dec 14 2011, 08:13
SPI отсылает и принимает ОДНОВРЕМЕННО.
Т.е. чтобы что-то принять, мастер должен что-то отослать.
//функция передачи байта
char SPI_MasterTransmit(char cData)
{
SPDR = cData;//начинаем передачу
while(!(SPSR & (1<<SPIF)));//ждем пока передача завершится
return SPDR;
}
Вызов:
receivedByte = SPI_MasterTransmit(0xFF);
arttab
Dec 15 2011, 01:27
есть такое. причем когда мастер только передает и входная линия физически отсутствует все равно надо читать из регистра ресивера. на меге8535 c этим столкнулся.
ADEPTPS
Dec 15 2011, 07:29
А как мне быть если ответом будет слово?
Сергей Борщ
Dec 15 2011, 07:43
QUOTE (arttab @ Dec 15 2011, 03:27)

есть такое. причем когда мастер только передает и входная линия физически отсутствует все равно надо читать из регистра ресивера. на меге8535 c этим столкнулся.
Странно. На меге8 считываю только тогда, когда нужны принятые данные. И все работает. И с прерываниями, и без. Вроде бы дата рождения у них примерно одинаковая, откуда же такое отличие?
QUOTE (ADEPTPS @ Dec 15 2011, 09:29)

А как мне быть если ответом будет слово?
Принять два байта и склеить из них двухбайтовую переменную?
ADEPTPS
Dec 15 2011, 07:52
судя по последней конструкции, один байт отдали - один приняли, а у меня один байт отдали - слово приняли
hd44780
Dec 15 2011, 09:09
SPI всегда и везде принимает только байты. По крайней мере, в AVR-ах.
Если надо слово, то:
word rWord = SPI_MasterTransmit(0xFF); /// Старший байт
rWord <<= 8;
rWord |= SPI_MasterTransmit(0xFF); // Младший
Если наоборот - сами напишете.
а у меня один байт отдали - слово приняли
----------------------------------------------------
SPI - синхронный интерфейс с линией СИНХРО. Данные (по ОПРЕДЕЛЕНИЮ!)
передвигаются из/в обычные сдвиговые регистры. Значит надо передать
поочередно два байта (один - пустой) и т.о. сформировать 8+8 синхроимпульсов,
по которым с другой стороны вытолкнутся к вам 8 +8 бит.
А вообще, прежде чем писать (и прогу и сюда) надо хотя бы картинки в DS посмотреть!
ADEPTPS
Dec 23 2011, 10:45
Посмотрите кто-нибудь мой код, если не трудно, на мой взгляд проблема в настройке SPI:
это подпрограмма для инициализации и считывания данных с АЦП AD7792.
Помогите пожалуйста!
CODE
#include <avr/io.h>
#include <avr/delay.h>
#include <string.h>
#include <avr/sfr_defs.h>
void spi_in(void)
{
#define DDR_SPI DDRB
#define DD_SS 0
#define DD_MOSI 2
#define DD_MISO 3
#define DD_SCK 1
#define SPE 6
#define MSTR 4
#define SPR0 0
#define SPIF 7
PORTB |= (1<<DD_SCK)|(1<<DD_MOSI)|(1<<DD_MISO);
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_MISO);
DDR_SPI &= ~(1<<DD_MISO);
//SPSR |= (1<<SPI2X);
SPCR |= (1<<SPE)|(1<<MSTR);
}
uint8_t spi_rw(uint8_t Data)
{
SPDR = Data;//начинаем передачу
while((SPSR & (1<<SPIF)) == 0);//ждем пока передача завершится
Data = SPDR;
return Data;
}
//Инициализация АЦП
void ad7793_init(void)
{
int8_t i;
spi_in();
for (i = 0; i < 4;i++) spi_rw(0xFF);
/* настройка АЦП */
spi_rw(0b00010000);
spi_rw(0b00010000);
spi_rw(0b00000000);
spi_rw(0b00101000);
spi_rw(0b00000000);
/* Калибровка */
spi_rw(0b00001000);
spi_rw(0b11000000);
spi_rw(0b10000001);
_delay_ms(10);
loop_until_bit_is_clear(PORTB,DD_MISO);
spi_rw(0b00001000);
spi_rw(0b10100000);
spi_rw(0b10000001);
_delay_ms(10);
loop_until_bit_is_clear(PORTB,DD_MISO);
}
//Установка режима работы
void ad7793_mode_set(unsigned char mode)
{
spi_rw(0b00001000);
if (mode == 0)
{
spi_rw(0b00000000);
}
else spi_rw(0b00100000);
spi_rw(0b10000001);
}
uint16_t ad7793_data_get(void)
{
uint16_t t = 0;
loop_until_bit_is_clear(PORTB,DD_MISO);
spi_rw(0x58);
*((uint8_t *)(&t) + 1) = spi_rw(0xFF);
*((uint8_t *)(&t)) = spi_rw(0xFF);
return t;
}
Цитата(usav @ Dec 16 2011, 16:21)

А вообще, прежде чем писать (и прогу и сюда) надо хотя бы картинки в DS посмотреть!
Их я уже насмотрелся....
Tolyaha
Dec 23 2011, 10:55
Цитата(ADEPTPS @ Dec 23 2011, 11:50)

Посмотрите кто-нибудь мой код
То что я увидел - нужно обратить внимание на сигнал SS (слейв селект PB4) он переключает режим из мастера в слейв низким уровнем на пине, если настроен как вход, если не собираетесь переключаться, то он не должен быть входом (ниже я настроил его выходом), и для этого АЦП, если вы подключаете SCK без инвертирования я поменял фазу и полярность. Попробуйте скорректированное мной (правда смотрел по быстрому, мог ошибиться проверте по даташиту:
CODE
void spi_in(void)
{
#define DDR_SPI DDRB
#define DD_SS 0
#define DD_MOSI 2
#define DD_MISO 3
#define DD_SCK 1
#define CPOL 3
#define CPHA 2
#define SPE 6
#define MSTR 4
#define SPR0 0
#define SPIF 7
PORTB |= (1<<DD_SCK)|(1<<DD_MOSI)|(1<<DD_MISO);
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
DDR_SPI &= ~(1<<DD_MISO);
//SPSR |= (1<<SPI2X);
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA);
}
P.S. А вобще в аврстудии есть инклюдник, описывающий все биты (m8535def.inc) или еще где можно найти и h файл с дефайнами (я думаю обязательно есть в для любой среды программирования)
ADEPTPS
Dec 23 2011, 11:04
Спасибо, сейчас попробую!
SPI завелся вроде, но на ЖКИ по прежнему 0...
Tolyaha
Dec 23 2011, 11:16
Цитата(ADEPTPS @ Dec 23 2011, 13:04)

Спасибо, сейчас попробую!
SPI завелся вроде, но на ЖКИ по прежнему 0...
Прошу прощения пошибся просто по тексту увидел Mega8535, а нада 128, тогда оставте это по старому, а остальное попробуйте
CODE
#define DD_SS 0
#define DD_MOSI 2
#define DD_MISO 3
#define DD_SCK 1
ADEPTPS
Dec 23 2011, 11:48
читается какая-то константа.... 12336 которая не зависит от входа на АЦП. но все равно большое спасибо!
вот немного поменял, выход с АЦП FFFF
Выкладываю обновленный код(без подпрограммы инициализации и вывода ЖКИ - он работает):
Подпрограмма АЦП:
CODE
#include <avr/io.h>
#include <avr/delay.h>
#include <string.h>
#include <avr/sfr_defs.h>
void spi_in(void)
{
#define DDR_SPI DDRB
#define CPOL 3
#define CPHA 2
#define SPE 6
#define MSTR 4
#define SPR0 0
#define SPIF 7
#define DD_SS 0
#define DD_MOSI 2
#define DD_MISO 3
#define DD_SCK 1
PORTB |= (1<<DD_SCK)|(1<<DD_MOSI)|(1<<DD_MISO);
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
DDR_SPI &= ~(1<<DD_MISO);
//SPSR |= (1<<SPI2X);
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA);
}
uint8_t spi_rw(uint8_t Data)
{
SPDR = Data;//начинаем передачу
while((SPSR & (1<<SPIF)) == 0);//ждем пока передача завершится
Data = SPDR;
return Data;
}
//Инициализация АЦП
void ad7793_init(void)
{
int8_t i;
spi_in();
for (i = 0; i < 4;i++) spi_rw(0xFF);
/* настройка АЦП */
spi_rw(0b00010000);
spi_rw(0b00010000);
spi_rw(0b00000000);
spi_rw(0b00101000);
spi_rw(0b00000000);
/* Калибровка */
spi_rw(0b00001000);
spi_rw(0b11000000);
spi_rw(0b10000001);
_delay_ms(10);
loop_until_bit_is_clear(DDR_SPI,DD_MISO);
spi_rw(0b00001000);
spi_rw(0b10100000);
spi_rw(0b10000001);
_delay_ms(10);
loop_until_bit_is_clear(DDR_SPI,DD_MISO);
}
//Установка режима работы
void ad7793_mode_set(unsigned char mode)
{
spi_rw(0b00001000);
if (mode == 0)
{
spi_rw(0b00000000);
}
else spi_rw(0b00100000);
spi_rw(0b10000001);
}
uint16_t t;
uint16_t ad7793_data_get(void)
{
t = 0;
loop_until_bit_is_clear(DDR_SPI,DD_MISO);
spi_rw(0x58);
t = (uint16_t)(spi_rw(0xFF) << 8);
t |= spi_rw(0xFF);
return t;
}
Главная программа:
CODE
#include <avr/io.h>
#include <avr/delay.h>
#include "lcd.h"
#include <stdio.h>
#include "adc2.c"
void main(void)
{
char text[6];
unsigned int n=0;
double adc;
lcd_init();
lcd_write("Autorising...");
ad7793_init();
DDRD = (1 << 4);
ad7793_mode_set(0);
seconds(1);
lcd_init();
lcd_write("Autorising...");
seconds(1);
while (1)
{
adc = ad7793_data_get();
seconds(1);
dtostrf(adc,6,0,text);
lcd_send(COMMAND, LCD_CLEAR);
DDRD = (1 << 4);
lcd_write(text);
DDRD = 0x00;
}
}
Tolyaha
Dec 23 2011, 11:59
Давай попорядку, проверим связь и прочитаем статус регистр и сравним с Power-On/Reset = 0x80 (AD7792)/0x88 (AD7793)
И просле сброса четырех 0xFF нада выдержать паузу необходимую для сброса 500мкс
Код
for (i = 0; i < 4;i++) spi_rw(0xFF);
_delay_ms(1);
/* настройка АЦП */
spi_rw(0b00010000);
spi_rw(0b00010000);
spi_rw(0b00000000);
spi_rw(0b00101000);
spi_rw(0b00000000);
ADEPTPS
Dec 23 2011, 12:09
у меня это получается _delay_ms(5000); = 500 мс
единички на месте)
а сори, многовато, микросекунды нужны тогда _delay_ms(5); так получается из-за того что тактовая частота не прописана (определено экспериментальным путем)
Tolyaha
Dec 23 2011, 12:23
Попрежнему хочу проверки связи, чтением статус регистраCODE
for (i = 0; i < 4;i++) spi_rw(0xFF);
_delay_ms(10);
/*проверкка связи с АЦП */
spi_rw(0x40);//настройка АЦП для чтения STATUS регистра
spi_rw(0xFF);//должно прочитаться 0x80 (AD7792)/0x88 (AD7793)
ADEPTPS
Dec 23 2011, 12:35
FF читает... значит связи нет(
Tolyaha
Dec 23 2011, 12:45
Цитата(ADEPTPS @ Dec 23 2011, 14:35)

FF читает... значит связи нет(
а осцыла нету? проверь хоть проц, когда закорачиваеш MISO (вход SPI) на общий должно вместо 0xFF читать 0x00
ADEPTPS
Dec 23 2011, 12:45
рабочий день заканчивается, буду завтра уже дальше разбираться... Спасибо!
цифровой осциллограф есть, но уже выходные...
ADEPTPS
Dec 26 2011, 07:54
И я снова здесь! Перекорачиваю MISO на общий, ноль появляется!
- Осцилограф показал, что НА MOSI, MISO и CLK висит постоянная "1". т.е. 5 В
АЦП имеет ногу Chip Select (CS), которой нужно "дрыгать" в определенные моменты... Что-то подобного я у Вас не нахожу... Плохо смотрел?
ADEPTPS
Dec 26 2011, 08:20
да, Вы правы, а когда нужно "дрыгать"?
hd44780
Dec 26 2011, 08:30
Цитата(ADEPTPS @ Dec 26 2011, 09:54)

НА MOSI, MISO и CLK висит постоянная "1". т.е. 5 В
На CLK (выход синхронизации) мастера (вашей Mega128) при передаче ВСЕГДА должны быть импульсы. Вне зависимоси от того, что вы передаёте - хоть нули, хоть что.
Если их нету, 2 варианта:
1. Неправильно сконфигурировали SPI.
2. "Неправильный" контроллер - брак, сгорел SPI и т.п.
Хотя, если бы он сгорел, то он наверняка бы и не прошивался ....
Цитата(ADEPTPS @ Dec 26 2011, 10:20)

когда нужно "дрыгать"?
1. CS=0 (м.б. 1 - уточите в ДШ на ваш АЦП).
2. Любой обмен данными
3. CS=1 (или 0).
Иначе АЦП просто пропустит ваши команди и всё остальное мимо ушей

.
Цитата(ADEPTPS @ Dec 26 2011, 12:20)

когда нужно "дрыгать"?
Установили СS в низкий - передали/прочитали нужное число байт для записи/чтения в регистр - поставили CS в высокий уровень.
Исключение можно сделать только для режима Continuous Read, ну ещё можно и для режима Continuous Conversion (для последнего - можно, но не обязательно). В этих режимах: CS - низкий в начале режима, по окончанию режима - высокий уровень.
Всё это описано/нарисовано в DS.
ADEPTPS
Dec 26 2011, 08:49
Спасибо, сейчас попробую!
Tolyaha
Dec 26 2011, 09:35
Ноль на CS обязательно, если АЦП рабочий, то на выходе данных (17 вывод) будет видна частота около 4 Hz (готовность данных). По умолчанию АЦП работает циклически с частотой 4Hz.
Вобще, если работаеш только с одним АЦП по этим линиям связи, то можно CS навсегда запаять на ноль.
ADEPTPS
Dec 26 2011, 11:38
SPI все же не работает, поскольку на CLK весит 5В ("еденичка"), вот что было последнее по настройке SPI (то что используется сейчас):
CODE
void spi_in(void)
{
#define DDR_SPI DDRB
/*#define CPOL 3
#define CPHA 2
#define SPE 6
#define MSTR 4
#define SPR0 0
#define SPIF 7 */
#define DD_SS 0
#define DD_MOSI 2
#define DD_MISO 3
#define DD_SCK 1
PORTB |= (1<<DD_SCK)|(1<<DD_MOSI)|(1<<DD_MISO);
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK)|(1<<DD_SS);
DDR_SPI &= ~(1<<DD_MISO);
//SPSR |= (1<<SPI2X);
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA);
}
uint8_t spi_rw(uint8_t Data)
{
SPDR = Data;//начинаем передачу
while((SPSR & (1<<SPIF)) == 0);//ждем пока передача завершится
Data = SPDR;
return Data;
}
Tolyaha
Dec 26 2011, 11:53
А как же это?
Цитата(ADEPTPS @ Dec 26 2011, 09:54)

И я снова здесь! Перекорачиваю MISO на общий, ноль появляется!
Может не заметили в осциллограф?
ADEPTPS
Dec 28 2011, 09:00
Цитата(Tolyaha @ Dec 26 2011, 15:53)

А как же это?
Может не заметили в осциллограф?
Но сигнал тактирования (CLK) то отсутствует....
еще раз проверил на осциллографе
Tolyaha
Dec 28 2011, 13:31
Цитата(ADEPTPS @ Dec 28 2011, 11:00)

Но сигнал тактирования (CLK) то отсутствует....
Если точно SCK отсутствует (а не осцил неправильно настроен), то вариантов 2:
- или Вы в программе кроме показанного участка порты перенастраиваете;
- или пин у контроллера не работает.
Если SPI чувствует FF или 00 ( при закорачивании) значит он включен и вход MISO работает.
Проверте осцилом порты SCK и MOSI (PB1, PB2) настраивая их на вывод 0 (может залепуха или пробой пина).
ADEPTPS
Dec 29 2011, 08:23
CLK поймал:
1. я снимал показания раз в секунду
2. после перенастройки на постоянное считывание, частота CLK ~ 2МГц.
Судя по далашиту АЦП, CLK дложен быть ~ 64 кГц
Перенастраиваю SPI...
- Получил CLK ~60кГЦ
- По MOSI тоже что-то передаю
- На MISO - постоянно 5В!!!!!!!!
Tolyaha
Dec 29 2011, 12:58
Стоп машина, а PB1 (SCK) МК куда у Вас подключен????? Он должен быть подключен к входу SCLK АЦП (пин 1). А на вход CLK (пин 2) АЦП можно подать 60кГЦ от другого источника (только не такт от SPI), а можно и не подавать и использвать внутренний генератор АЦП.
Схему покажете, меньше вопросов будет.
ЗЫ: CS АЦП подключи на общий, и на 15 пине АЦП (DOUT), который должен быть подключен к MISO МК, исправный АЦП по умолчанию будет выдавать 4 Hz частоту.
ADEPTPS
Dec 29 2011, 14:14
Подсоединено все правильно, так как использую отладочную плату AS-megaCU.
Схема с сайта производителя (PDF)-
Общая информация об отладочной плате//////Похоже одна проблема ясна: Я ничего не подаю на CLK и в настройках указал использовать External source 64kHZ
ADEPTPS
Dec 30 2011, 06:15
Настроил внутренний источник 64кГЦ, эффект тот же, попробовал вывести частоту на CLK - на осциллографе 0В....
Tolyaha
Dec 30 2011, 06:41
Цитата(ADEPTPS @ Dec 29 2011, 16:14)

//////Похоже одна проблема ясна: Я ничего не подаю на CLK и в настройках указал использовать External source 64kHZ
По схеме на SPI висят еще микросхемы ЦАП и FLASH.
Чтобы небыло конфликта предлагаю так:
- выключить ЦАП и FLASH, PB7 и PE7 настраиваем на выход лог. "1";
- включаем АЦП, PE2 настраиваем на выход лог. "0".
Потом проверяем связь, как предлогалось ранее (чтением статус регистра).
Дальше работаем с АЦП от внутреннего (Internal 64 kHz Clock.) CLK.
Позднее, если необходимо, можно подать и внешний такт от таймера 3 МК на выход OC3A (например режим Clear Timer on Compare Match (CTC) Mode).
Успехов и всех с наступающим Новым годом!
ADEPTPS
Dec 30 2011, 06:42
ЦАП и FLASH - опционально устанавливаются - ИХ НЕТ!!!
из дополнительных есть только опорник и АЦП!
И Вас с Наступающим!!!
Tolyaha
Dec 30 2011, 07:03
Тогда проверяем связь.
CODE
PORTB = 0xff;
DDRB = 0x87;
PORTE = 0x80;
DDRE = 0x84;
#define CPOL 3
#define CPHA 2
#define SPE 6
#define MSTR 4
#define SPR0 0
#define SPIF 7
SPCR |= (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA);
for (i = 0; i < 4;i++) spi_rw(0xFF);
_delay_ms(1000);
/*проверкка связи с АЦП */
spi_rw(0x40);//настройка АЦП для чтения STATUS регистра
spi_rw(0xFF);//должно прочитаться 0x80 (AD7792)/0x88 (AD7793)
uint8_t spi_rw(uint8_t Data)
{
SPDR = Data;//начинаем передачу
while((SPSR & (1<<SPIF)) == 0);//ждем пока передача завершится
Data = SPDR;
return Data;
}
Пробуем, если не попутал должно прочитать 0x80 (AD7792)/0x88 (AD7793)
ADEPTPS
Dec 30 2011, 07:37
выдает 0... АЦП что-ли накирнулось...
Tolyaha
Dec 30 2011, 07:47
Цитата(ADEPTPS @ Dec 30 2011, 09:37)

выдает 0... АЦП что-ли накирнулось...
Проверяем АЦП:
Код
PORTB = 0xff;
DDRB = 0x87;
PORTE = 0x80;
DDRE = 0x84;
и смотрим осциллографом на пинах АЦП:
3 пин -0;
1,16 пин -1;
15 пин - частота 4 Hz.
ADEPTPS
Jan 10 2012, 05:00
3 пин -0; - есть!!!
1,16 пин -1; - есть!!!
15 пин - частота 4 Hz. - нет!!!!!!!!!!!!
- Всех с прошедшими праздниками!
Вышел на работу... по прежнему сдвигов нету..
Tolyaha
Jan 10 2012, 07:46
Цитата(ADEPTPS @ Jan 10 2012, 07:00)

15 пин - частота 4 Hz. - нет!!!!!!!!!!!!
Значит АЦП не работает. Правда я ошибся там не 4 Hz должно быть, а 16 Hz.
ADEPTPS
Jan 10 2012, 08:34
тогда придется перепаивать...
yanvasiij
Sep 25 2013, 10:16
Люди, если все получилось поделитесь исходниками для работы с ad7792, если не жаль
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.