Например TDA7294

Форум РадиоКот • Просмотр темы - Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО]
Форум РадиоКот
Здесь можно немножко помяукать :)

Текущее время: Пт окт 03, 2025 12:57:15

Часовой пояс: UTC + 3 часа


ПРЯМО СЕЙЧАС:



Начать новую тему Ответить на тему  [ Сообщений: 3 ] 
Автор Сообщение
Не в сети
 Заголовок сообщения: Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО]
СообщениеДобавлено: Вт ноя 08, 2016 13:45:06 
Родился

Зарегистрирован: Ср ноя 02, 2016 09:22:08
Сообщений: 4
Откуда: Пенза
Рейтинг сообщения: 0
Всем доброго времени суток, уважаемые форумчане!

Всё время старался разбираться сам, если возникают какие либо проблемы в познании такого ремесла, как программирование МК, но настало то время, когда без помощи более мудрых наставников никак не обойтись.

История началась с того, что программированием я занимаюсь меньше года, за это время успел освоить asm в любительской форме, а тут по работе нужда возникла перейти с PIC-ов на STM, заказали платы отладочные для экспериментов, вроде всё хорошо. Но возникла необходимость самим спаять плату с акселерометром LIS3DH на борту, а для управления взять камень STM32F302C6T6 (управление по шине SPI).

Плата готова, элементы напаяны, решаю начать с настройки тактирования от внешнего кварца и с типичного мигания светодиодом, дабы подтвердить работоспособность камня. Среда - keil uvision 5, библиотека - SPL.
Код:
int main(void)
{
   RCC_Configuration();

//----------
//   Тактирование светодиодов
//----------
   LEDS_ini();
//----------
//                     DELAY INIT
//----------
   SysTick_Config(SystemCoreClock / 4000); // настройка появлений прерывания от SysTick на время 1ms
   delay_ms(1000);

   while(1)   
   {

      RED_ON;
      delay_ms(500);
      RED_OFF;
      delay_ms(500);
   }
}


Инициализация порта под светодиод и настройка тактирования от внешнего кварца:
Код:
#include "mcu_ini.h"

//=====================
//
//=====================
ErrorStatus HSEStartUpStatus;
RCC_ClocksTypeDef RCC_Clocks;

void RCC_Configuration(void)
{
      
      RCC_DeInit();                                               // Выполняем сброс reset
    RCC_HSEConfig(RCC_HSE_ON);                                  // Включаем тактирование HSE (от кварца)
    HSEStartUpStatus = RCC_WaitForHSEStartUp();                 // Ждем пока частота кварца стабилизируется

    if (HSEStartUpStatus == SUCCESS)                            // Если все отлично, то переходим на кварц
    {
        RCC_HCLKConfig(RCC_SYSCLK_Div2);               
        RCC_PCLK2Config(RCC_HCLK_Div1);                         // Запитываем APB2 от тактовой частоты PLL в 16 МГц
        RCC_PCLK1Config(RCC_HCLK_Div1);                         // Запитываем APB1 от тактовой частоты PLL в 16 МГц
        RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div1);
            RCC_USARTCLKConfig(RCC_USART1CLK_PCLK);
        RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_4);     // Устанавливаем множитель частоты 4
            RCC_PREDIV1Config(RCC_PREDIV1_Div1);
       
        RCC_PLLCmd(ENABLE);                                     // Включаем PLL
       
        while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}  // Ждем пока PLL устаканится
       
        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              // Выбираем PLL как источник тактового сигнала

       
        while (RCC_GetSYSCLKSource() != 0x08) {}                // Ждем пока PLL установится как источник тактирования
            RCC_HSICmd(DISABLE);
    }
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF,ENABLE);
}
//=====================
//
//=====================
void LEDS_ini(void)
{
   GPIO_InitTypeDef GPIO_init_LED;
   
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);
   
   GPIO_init_LED.GPIO_Mode = GPIO_Mode_OUT;
   GPIO_init_LED.GPIO_OType = GPIO_OType_PP;
   GPIO_init_LED.GPIO_Pin = GPIO_Pin_1;
   GPIO_init_LED.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_init_LED.GPIO_Speed = GPIO_Speed_2MHz;
   
   GPIO_Init(GPIOA,&GPIO_init_LED);
}


Всё работает. Думаю, уже хорошо, можно настроить SPI и опросить регистр WHO_I_AM акселерометра, пишу:
- инициализация SPI2
Код:
void SPI_ini(void)
{
   GPIO_InitTypeDef          GPIO_init_SPI;
   SPI_InitTypeDef            SPI_init_user;
   
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
   
   //=====================      
   GPIO_init_SPI.GPIO_Mode = GPIO_Mode_AF;
   GPIO_init_SPI.GPIO_OType = GPIO_OType_PP;
   GPIO_init_SPI.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
   GPIO_init_SPI.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_init_SPI.GPIO_PuPd = GPIO_PuPd_UP;
   
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_5); //настройка альтернативной функции ножек порта
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_5);
   GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_5);

   //===================== Chip Select
   GPIO_init_SPI.GPIO_Mode = GPIO_Mode_OUT;
   GPIO_init_SPI.GPIO_OType = GPIO_OType_PP;
   GPIO_init_SPI.GPIO_Pin = GPIO_Pin_12;
   GPIO_init_SPI.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_init_SPI.GPIO_PuPd = GPIO_PuPd_UP;

   GPIO_Init(GPIOB,&GPIO_init_SPI);
  //=====================
   CS_OFF;
   //=====================
   SPI_I2S_DeInit(SPI2);
   
   SPI_init_user.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
   SPI_init_user.SPI_CPHA = SPI_CPHA_1Edge;
   SPI_init_user.SPI_CPOL = SPI_CPOL_Low;
   SPI_init_user.SPI_CRCPolynomial = 7;
   SPI_init_user.SPI_DataSize = SPI_DataSize_8b;
   SPI_init_user.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
   SPI_init_user.SPI_FirstBit = SPI_FirstBit_MSB;
   SPI_init_user.SPI_Mode = SPI_Mode_Master;
   SPI_init_user.SPI_NSS = SPI_NSS_Soft;
   
   
   SPI_Init(SPI2,&SPI_init_user);
   //=====================
   
   SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF);
 
  SPI_DataSizeConfig(SPI2, ENABLE);
   
   SPI_Cmd(SPI2,ENABLE);

   SPI_NSSInternalSoftwareConfig(SPI2, SPI_NSSInternalSoft_Set);


Для пояснения: CS - это нога акселерометра, отвечающая за выбор типа обмена (SPI или I2C). Сам обмен осуществляется только после подтягивания данной ноги к земле, после окончания передачи нога снова подтягивается к питанию.

Код:
#define   CS_ON                           GPIO_ResetBits(GPIOB,GPIO_Pin_12);
#define   CS_OFF                        GPIO_SetBits   (GPIOB,GPIO_Pin_12);


Функция для чтения данных:
Код:
//Передача данных
uint8_t Send_data (uint8_t byteToSend)
   {
      while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) {}
         
      SPI_SendData8(SPI2,byteToSend);
         
      while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){}   
         
      return (uint8_t)SPI_ReceiveData8(SPI2);      
   }
//Функция чтения данных (addr - адрес)
   
uint8_t   Read_data (uint8_t addr)
   {   
      uint8_t temp_byte;
      
      CS_ON;
   
      Send_data (addr);
   
      temp_byte = Send_data (DUMMY_BYTE);
   
      CS_OFF;

      return temp_byte;      
   }


Программа для опроса регистра:
Код:
void   Accel_Ini (void)
   {
   uint8_t Accel_ID;
//----------
//   Проверка акселерометра опросом его ID.
//   При верном полученном значении происходит инициализация
///----------
      Accel_ID = Read_data(LIS3DSH_WHO_I_AM_ADDR);
      
         if (Accel_ID == 0x33)
         {
            RED_ON;
            delay_ms(500);
            RED_OFF;
            Accel_setup ();         
         }
         else
         {
            Error();
         }
   }


И сам main:
Код:
int main(void)
{
   RCC_Configuration();

//----------
//   Тактирование светодиодов
//----------
   LEDS_ini();
//----------
//                     DELAY INIT
//----------
   SysTick_Config(SystemCoreClock / 4000); // настройка появлений прерывания от SysTick на время 1ms
   delay_ms(1000);
//----------
//----------
//                     SPI INIT
//----------   
   SPI_ini();
//----------

//=====================
   while(1)   
   {
      Accel_Ini();
   }
}


Прошиваю, запускаю: не работает. висит на опросе
Код:
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET){}   

Лезу с осциллографом на ногу SCK, по которой осуществляется тактирование SPI, там пусто. Пробую тот же самый код, но немного переделанный под отладочную плату STM32F3Discovery и опрашиваю гироскоп L3GD20, который там стоит. Всё опрашивается, и значение с регистра приходит то, которое нужно. Иду дальше, пробую создать проект в STM32Cube, меняю функции SPL-я на HAL-овские, зашиваю свой камень, SPI работает. Опрос происходит, данные приходят те, которые нужны.

В связи с этим вопрос к знающим котам: где может быть ошибка в листинге, который написан с помощью SPL? Возможно что то не включил ещё дополнительное?
Был бы очень благодарен за помощь!
PS: знаю, что некоторые люди скажут, мол "SPL,HAL - всё не то, CMSIS - вот решение проблем", я с ними соглашусь, но на углубленное изучение регистров и работы с ними времени надо достаточно, а у меня его на данный момент не так много, так что жду помощи :)
PS2: если вдруг нужен проект целиком, сообщите, я не жадный :)

UPDT: Я понял секрет решения проблем. Создаешь тему и ждешь, пока ответ найдется сам :)

Если вдруг кому-то будет интересен данный топик, то проблема в итоге решена:
Дело оказалось в основном в аппаратной части, по неопытности и малограмотности по семейству STM, я для удобства проектирование ПП вывод CS подключил на аппаратный NSS SPI2, думая, что раз я данный вывод не использую, то можно смело его задействовать в качестве стандартного порта ввода/вывода. Однако ТАК сие изделие у меня не заработало. Пришлось вывод перенести на другую свободную ногу. Однако про настройку NSS забывать не стоит:
Код:
SPI_I2S_DeInit(SPI2);
   
   SPI_init_user.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
   SPI_init_user.SPI_CPHA = SPI_CPHA_2Edge;
   SPI_init_user.SPI_CPOL = SPI_CPOL_High;
   SPI_init_user.SPI_CRCPolynomial = 7;
   SPI_init_user.SPI_DataSize = SPI_DataSize_8b;
   SPI_init_user.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
   SPI_init_user.SPI_FirstBit = SPI_FirstBit_MSB;
   SPI_init_user.SPI_Mode = SPI_Mode_Master;
   SPI_init_user.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
   
   SPI_Init(SPI2,&SPI_init_user);
   //=====================
   
   SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_QF);
 
        SPI_DataSizeConfig(SPI2, ENABLE);
   
   SPI_Cmd(SPI2,ENABLE);


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО]
СообщениеДобавлено: Вт ноя 08, 2016 16:04:06 
Вымогатель припоя
Аватар пользователя

Карма: -2
Рейтинг сообщений: -32
Зарегистрирован: Вс ноя 01, 2015 13:13:49
Сообщений: 616
Рейтинг сообщения: 0
A-Stim писал(а):
для удобства проектирование ПП вывод CS подключил на аппаратный NSS SPI2, думая, что раз я данный вывод не использую, то можно смело его задействовать в качестве стандартного порта ввода/вывода. Однако ТАК сие изделие у меня не заработало. Пришлось вывод перенести на другую свободную ногу.

Не разобрались до конца с настройками SPI. Можно смело его задействовать в качестве стандартного порта ввода/вывода.


Вернуться наверх
 
Не в сети
 Заголовок сообщения: Re: Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО]
СообщениеДобавлено: Ср ноя 09, 2016 14:30:17 
Родился

Зарегистрирован: Ср ноя 02, 2016 09:22:08
Сообщений: 4
Откуда: Пенза
Рейтинг сообщения: 0
scorpi_0n писал(а):
A-Stim писал(а):
для удобства проектирование ПП вывод CS подключил на аппаратный NSS SPI2, думая, что раз я данный вывод не использую, то можно смело его задействовать в качестве стандартного порта ввода/вывода. Однако ТАК сие изделие у меня не заработало. Пришлось вывод перенести на другую свободную ногу.

Не разобрались до конца с настройками SPI. Можно смело его задействовать в качестве стандартного порта ввода/вывода.

Тогда вопрос, как можно было это сделать?
Я до этого использовал:
Код:
   SPI_NSSInternalSoftwareConfig(SPI2, SPI_NSSInternalSoft_Set);

Имеет ли значение то, что я использовал эту функцию до
Код:
 SPI_Cmd(SPI2,ENABLE);
или нет?


Вернуться наверх
 
Показать сообщения за:  Сортировать по:  Вернуться наверх
Начать новую тему Ответить на тему  [ Сообщений: 3 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 37


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Перейти:  


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
Русская поддержка phpBB
Extended by Karma MOD © 2007—2012 m157y
Extended by Topic Tags MOD © 2012 m157y