Setup
I will present the code to read analog values from a pin on the STM32 and my setup to test the code. I'll use the most simple program that I could write to do the following: reading a single value from the ADC peripheral and display it on 12 LEDs (it is a 12-bit value).
There are more sophisticated methods of using the ADC, e.g. direct memory access (DMA), and I plan to use these later. First, a picture of the setup
Sampling frequency
One interesting aspect is the sampling frequency of the setup. I believe that one can calculate it based on information that is available in the datasheet, but I'm too lazy to do that now and will just measure it roughly: after each sample, a LED is toggled (too fast for the human eye). On the oscilloscope, it is possible to see the toggling frequency. The timescale in the picture is 10 us / div, so I have ~25 us / sample, which corresponds to ~40 kHz sampling rate.
Firmware
The firmware code is based on the STM32F103RB-Nucleo examples that are part of the STM32Cube_FW_F1_V1.3.0 package from where I copy/pasted it together. I'm running the chip with 72 MHz, generated from the 16MHz crystal on my test board. The code is all in the following main.c. It compiles with the makefile shown in my previous post./** ****************************************************************************** * based on: * Projects/STM32F103RB-Nucleo/Examples/GPIO/GPIO_IOToggle/Src/main.c * from the STM32Cube_FW_F1_V1.3.0 software package package ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ #include "stm32f1xx.h" #include "stm32f1xx_hal.h" void SysTick_Handler(void) { HAL_IncTick(); } void SystemClock_Config(void) { // Configure PLL with HSE_VALUE = 16000000UL = 16 MHz // PLL configuration: // PLLCLK = (HSE / 2) * PLLMUL = (16 / 2) * 9 = 72 MHz RCC_OscInitTypeDef oscinitstruct = {0}; oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; oscinitstruct.HSEState = RCC_HSE_ON; oscinitstruct.LSEState = RCC_LSE_OFF; oscinitstruct.HSIState = RCC_HSI_OFF; oscinitstruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV2; oscinitstruct.PLL.PLLState = RCC_PLL_ON; oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9; HAL_RCC_OscConfig(&oscinitstruct); // Select PLL as system clock source and configure // the HCLK, PCLK1 and PCLK2 clocks dividers RCC_ClkInitTypeDef clkinitstruct = {0}; clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1; clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV2; clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2); } void ConfigureADC(ADC_HandleTypeDef *AdcHandle) { GPIO_InitTypeDef gpioInit; __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_ADC1_CLK_ENABLE(); gpioInit.Pin = GPIO_PIN_1; gpioInit.Mode = GPIO_MODE_ANALOG; gpioInit.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &gpioInit); AdcHandle->Instance = ADC1; AdcHandle->Init.ScanConvMode = DISABLE; AdcHandle->Init.ContinuousConvMode = ENABLE; AdcHandle->Init.DiscontinuousConvMode = DISABLE; AdcHandle->Init.NbrOfDiscConversion = 0; AdcHandle->Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_CC1; AdcHandle->Init.DataAlign = ADC_DATAALIGN_RIGHT; AdcHandle->Init.NbrOfConversion = 1; HAL_ADC_Init(AdcHandle); ADC_ChannelConfTypeDef adcChannel; adcChannel.Channel = ADC_CHANNEL_1; adcChannel.Rank = 1; adcChannel.SamplingTime = ADC_SAMPLETIME_7CYCLES_5; //adcChannel.Offset = 0; if (HAL_ADC_ConfigChannel(AdcHandle, &adcChannel) != HAL_OK) { //asm("bkpt 255"); } } void display(uint32_t value) { if (value & (1<<0)) HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET); if (value & (1<<1)) HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET); if (value & (1<<2)) HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET); if (value & (1<<3)) HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET); if (value & (1<<4)) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_6,GPIO_PIN_RESET); if (value & (1<<5)) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_7,GPIO_PIN_RESET); if (value & (1<<6)) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8,GPIO_PIN_RESET); if (value & (1<<7)) HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOC,GPIO_PIN_9,GPIO_PIN_RESET); if (value & (1<<8)) HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET); if (value & (1<<9)) HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOA,GPIO_PIN_9,GPIO_PIN_RESET); if (value & (1<<10)) HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOA,GPIO_PIN_10,GPIO_PIN_RESET); if (value & (1<<11)) HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET); else HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET); } int main(void) { // STM32F103xB HAL library initialization: // - Configure the Flash prefetch // - Systick timer is configured by default as source of time base, but user // can eventually implement his proper time base source (a general purpose // timer for example or other time source), keeping in mind that Time base // duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and // handled in milliseconds basis. // - Set NVIC Group Priority to 4 // - Low Level Initialization HAL_Init(); // Configure the system clock to 72 MHz SystemClock_Config(); // -1- Enable GPIO Clock (to be able to program the configuration registers) __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); // -2- Configure IO in output push-pull mode to drive external LEDs GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // Configure the ADC peripheral ADC_HandleTypeDef AdcHandle; ConfigureADC(&AdcHandle); for (;;) { // ADC measurment & display value HAL_ADC_Start(&AdcHandle); HAL_ADC_PollForConversion(&AdcHandle, 1000); // 1000 is timeout in miliseconds display(HAL_ADC_GetValue(&AdcHandle)); HAL_ADC_Stop(&AdcHandle); // flash an additional LED to measure the sampling rate HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_4); } }
Keine Kommentare:
Kommentar veröffentlichen