Форум РадиоКот https://radiokot.ru/forum/ |
|
Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО] https://radiokot.ru/forum/viewtopic.php?f=59&t=137525 |
Страница 1 из 1 |
Автор: | A-Stim [ Вт ноя 08, 2016 13:45:06 ] |
Заголовок сообщения: | Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО] |
Всем доброго времени суток, уважаемые форумчане! Всё время старался разбираться сам, если возникают какие либо проблемы в познании такого ремесла, как программирование МК, но настало то время, когда без помощи более мудрых наставников никак не обойтись. История началась с того, что программированием я занимаюсь меньше года, за это время успел освоить 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); |
Автор: | scorpi_0n [ Вт ноя 08, 2016 16:04:06 ] |
Заголовок сообщения: | Re: Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО] |
A-Stim писал(а): для удобства проектирование ПП вывод CS подключил на аппаратный NSS SPI2, думая, что раз я данный вывод не использую, то можно смело его задействовать в качестве стандартного порта ввода/вывода. Однако ТАК сие изделие у меня не заработало. Пришлось вывод перенести на другую свободную ногу. Не разобрались до конца с настройками SPI. Можно смело его задействовать в качестве стандартного порта ввода/вывода. |
Автор: | A-Stim [ Ср ноя 09, 2016 14:30:17 ] |
Заголовок сообщения: | Re: Проблемы с SPI на МК STM32F302C6T6 [РЕШЕНО] |
scorpi_0n писал(а): A-Stim писал(а): для удобства проектирование ПП вывод CS подключил на аппаратный NSS SPI2, думая, что раз я данный вывод не использую, то можно смело его задействовать в качестве стандартного порта ввода/вывода. Однако ТАК сие изделие у меня не заработало. Пришлось вывод перенести на другую свободную ногу. Не разобрались до конца с настройками SPI. Можно смело его задействовать в качестве стандартного порта ввода/вывода. Тогда вопрос, как можно было это сделать? Я до этого использовал: Код: SPI_NSSInternalSoftwareConfig(SPI2, SPI_NSSInternalSoft_Set); Имеет ли значение то, что я использовал эту функцию до Код: SPI_Cmd(SPI2,ENABLE); или нет?
|
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |