Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32_SPI_AD7794
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
nx6310
Связь STM32 c АЦП AD7794 через SPI. Использую стандартные библиотеки от производителя.Прога на Atomic TrueStudio (аналог Eclipse ). Для чтения из АЦП 24 битных данных использую псоледовательно прием 3 байтов. При этом они получаются абсолютно одинаковыми по значению. Кто нибудь сталкивался с этим?
AHTOXA
Чтобы прочитать байт из SPI, надо записать туда какой-либо байт. Вы это учли?
nx6310
Я пользуюсь стандартной библиотечной функцией. АЦП нормально преобразует. На его входе акселерометр стоит, при его наклоне данные с АЦП меняются. Даные по SPI конроллер получает. Только они дублируются. Я последовательно получаю старшый байт, средний байт и младший байт. В итоге должно получиться 24-х разрядное число. Но уменя все эти три байта одинаковые. Не знаю даже в чем ошибся.
AHTOXA
Давайте код, посмотрим.
nx6310
Вот код. АЦП в режиме постоянного преобразования.
Код
     while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){}
        // SPI_I2S_SendData(SPI2, 0b01011000);
    //GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_SET);
// while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_8)!=0){}    //проверка окончания преобразования
  //GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET);
         while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
      ADCL = SPI_I2S_ReceiveData(SPI2);
     // while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==RESET){}
      //Delay(0x6ffff);
       ADCM = SPI_I2S_ReceiveData(SPI2);
     // while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==0){}
        //  Delay(0x6ffff);
       ADCH = SPI_I2S_ReceiveData(SPI2);
     // while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE)==0){}
      //GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_SET);
      ADC_Data=ADCH*0x10000+ADCM*0x100+ADCL;

Ниже стандартные библиотечные функции обмена по SPI
Код
void SPI_I2S_SendData(SPI_TypeDef* SPIx, uint16_t Data)
{
  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
  
  /* Write in the DR register the data to be sent */
  SPIx->DR = Data;
}

/**
  * @brief  Returns the most recent received data by the SPIx/I2Sx peripheral.
  * @param  SPIx: where x can be
  *   - 1, 2 or 3 in SPI mode
  *   - 2 or 3 in I2S mode
  * @retval The value of the received data.
  */
uint16_t SPI_I2S_ReceiveData(SPI_TypeDef* SPIx)
{
  /* Check the parameters */
  assert_param(IS_SPI_ALL_PERIPH(SPIx));
  /* Return the data in the DR register */
  return SPIx->DR;
}
AHTOXA
Цитата(nx6310 @ Jul 8 2010, 08:38) *
Код
     while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){}
         while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
      ADCL = SPI_I2S_ReceiveData(SPI2);
       ADCM = SPI_I2S_ReceiveData(SPI2);
       ADCH = SPI_I2S_ReceiveData(SPI2);
      ADC_Data=ADCH*0x10000+ADCM*0x100+ADCL;


Мда... Повторяю свою первую реплику:

Цитата(AHTOXA @ Jul 7 2010, 16:59) *
Чтобы прочитать байт из SPI, надо записать туда какой-либо байт. Вы это учли?


Где запись перед чтением?

Код
    SPI_I2S_SendData(SPI2, 0);
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
    ADCL = SPI_I2S_ReceiveData(SPI2);

    SPI_I2S_SendData(SPI2, 0);
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
    ADCM = SPI_I2S_ReceiveData(SPI2);

    SPI_I2S_SendData(SPI2, 0);
    while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET);
    ADCH = SPI_I2S_ReceiveData(SPI2);
demiurg_spb
Да. Стандартная наколка spi-нубов:-)
Чем SPI хорош - это просто тупейший сдвиговй регистр как у мастера так и у слейва, соединённые в кольцо.
И для произведения обмена этими регистрами (по сути ни чтения ни записи отдельно не существует) нужны тактовые имульсы в размере N-штук, где N-разрядность регистра.
Ну и конечно же нужно выбрать того слейва с кем хочется пообщаться - для этого используют столько линии #CS сколько есть слейвов.
Вот и вся премудрость:-)

ИМХО SPI - самый примитивный интерфейс вообще.
nx6310
А как переключать каналы в АЦП. Я выбираю канал, потом идёт задержка и после этого только преобразование. Но у меня вместо нормального значения выводятся FFFF. Как правильно это делается?
demiurg_spb
Вы datasheet вообще-то открывали?
Уж больно странные вопросы Вы задаёте, даже для раздела начинающих.
Почитайте подумайте, попробуйте.
Если не получилось, то расскажите что и как делали, покажите код, покажите Вашу схему включения.
Иначе долго будете топтаться на месте.
nx6310
Даташит читал. Сначала иницилизирую АЦП. Включаю буфер. Мне надо шесть каналов три на ферозонды три на акселерометры. опора внешняя на 2,5В. использую внутренний генератор.
код инициализации АЦП
Код
void ADC_Configuration(void){
      int i=0b0000000000110000;
GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET); // выбор АЦП CS_AD7794
    SPI_I2S_SendData(SPI2, 0b0000000000101000);    //в буферный регистр (к регистру IO)
     SPI_I2S_SendData(SPI2, 0b0000000000000000);    //настройка выводов АЦП
while (i<=0b0000000000110101){      // здесь циклически калибрую каждый канал ацп по нулю и полной шкале
        SPI_I2S_SendData(SPI2, 0b0000000000010000);    //comunic reg
        SPI_I2S_SendData(SPI2,i);    //config reg ADC - конфигурирую АЦП
        SPI_I2S_SendData(SPI2, 0b0000000000001000);    //comunic reg
        SPI_I2S_SendData(SPI2,0b1000001000001111);    //mode reg ADC IZC-call калибровка нуля
    while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){}    //проверка окончания преобразования (вывод DOUT/RDY)
                 SPI_I2S_SendData(SPI2, 0b0000000000001000);    //comunic reg
                   SPI_I2S_SendData(SPI2, 0b1010001000001111);    //mode reg ADC IFC-call калибровка полной шкалы
             while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){}    //проверка окончания преобразования
      GPIO_WriteBit(GPIOB, GPIO_Pin_12, Bit_RESET);
      i++;
    }
               SPI_I2S_SendData(SPI2, 0b0000000000001000);    //comunic reg после окончания калибровки каждого канала
      SPI_I2S_SendData(SPI2,0b0000001000000110);    //mode reg ADC default mode перевожу АЦП в режим непрерыного преобразования
}


В ходе выполнения программы мне необходимы данные со всех каналов. Кусок получения данных из АЦП для двух каналов представлен ниже


Код
SPI_I2S_SendData(SPI2, 0b0000000000010000);            //комуникац регистр. выбираю регистр конфигурации
SPI_I2S_SendData(SPI2, (0b0000000000010000));        //в котором выбираю канал 0 (буфер включён)
SPI_I2S_SendData(SPI2, 0b0000000001011100);        //в комуникац регистр запрос на получение данны х с АЦП
        while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){} // есть ли готовые данные в ацп
            AX = SPI_I2S_ReceiveData(SPI2); // считываем старшие 16 бит с АЦП - информативные данные
            Delay(0xaf);
            SPI_DataSizeConfig(SPI2, SPI_DataSize_8b);  // переводим SPi в 8-битный режим
            hrn = SPI_I2S_ReceiveData(SPI2);   // ситываю оставшиеся 8 бит, в этом байте мусор который я не использую
            SPI_DataSizeConfig(SPI2, SPI_DataSize_16b);


SPI_I2S_SendData(SPI2, 0b0000000000010000);            //комуникац регистр.
SPI_I2S_SendData(SPI2, 0b0000000000010001);        //регистр конфигурации выбираю канал 1
Delay(0xfff);                                    // задержка после выбора канала для разрядки конденсатора АЦП, какое бы значение не ставил не помогает
SPI_I2S_SendData(SPI2, 0b0000000001011100);        //режим постоянного преобр.
        while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){} // есть ли готовые данные в ацп
            AY = SPI_I2S_ReceiveData(SPI2);  // считываем старшие 16 бит с АЦП - информативные данные
            Delay(0xaf);
            SPI_DataSizeConfig(SPI2, SPI_DataSize_8b);
            hrn = SPI_I2S_ReceiveData(SPI2);
            SPI_DataSizeConfig(SPI2, SPI_DataSize_16b);



при считывании данных по USART получаю следующее
Код
Test_AX032934_AY065535_AZ032255_FX032255_FY065535_FZ065535_
Test_AX032932_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032932_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032932_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032930_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032930_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032930_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032932_AY065535_AZ065535_FX065535_FY065535_FZ065535_
Test_AX032930_AY065535_AZ065535_FX065535_FY065535_FZ065535_

По отдельности каждый канал работает нормально. Но вот при переключении каналов получается такая каша. Микроконтроллер STM32f103. Где я мог ошибиться?
AHTOXA
Цитата(nx6310 @ Jul 12 2010, 17:28) *
Код
    while (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_6)!=0){} // есть ли готовые данные в ацп
    AY = SPI_I2S_ReceiveData(SPI2);  // считываем старшие 16 бит с АЦП - информативные данные

cranky.gif
А где запись в SPI, которая так необходима для считывания?! Ведь я уже два раза выше это написал, пример привёл. Потом ещё demiurg_spb разъяснил...
nx6310
Она в нутри функции SPI_I2S_ReceiveData(SPI2) в библиотеку засунул я её. С SPI разобрался, данные передаются и принимаются Спасибо вам большое!!!. Шяс проблема с переключением каналов АЦП. Отдельно по каждому коналу данные принимаются нормально (если один канал исчпользовать). В многоканальном режиме полная хрень получаетсяsad.gif
AHTOXA
Цитата(nx6310 @ Jul 13 2010, 00:05) *
Она в нутри функции SPI_I2S_ReceiveData(SPI2) в библиотеку засунул я её.

А, понятно. Это зря, на мой взгляд. Библиотеку лучше было не трогать, лучше было написать свою функцию. Чтоб не запутаться потом.

Что касается нынешней проблемы - она оттого, что вы неверно читаете готовность АЦП.
Функция GPIO_ReadOutputDataBit(), которую вы используете, читает состояние выходной защёлки порта. То есть, то, что вы записали в этот порт. А для чтения входа надо применять функцию GPIO_ReadInputDataBit().
nx6310
функцию GPIO_ReadInputDataBit() поменял. Длительность преобразования изменилась. Но вот проблема с переключением кналов осталась.
AHTOXA
Цитата(nx6310 @ Jul 13 2010, 10:23) *
функцию GPIO_ReadInputDataBit() поменял.

Везде? В инициализации тоже?
Я не работал с этим АЦП, потому больше не могу помочь. Единственное что скажу - непрерывный режим тут не совсем к месту.
nx6310
Косяк был всё таки в SPI. Я думал что библиотечные функции STM включают весь цикл преобразования. ошибся. У пиковских библиотек всё цивильно, внутри проверяются все нужые флаги и т. д. А в этих библиотеках только процедуры записи и чтения из регистра данных SPI.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.