| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| |
| #include <hal/hal_bsp.h> |
| #include <assert.h> |
| #include "os/mynewt.h" |
| #include <mcu/cmsis_nvic.h> |
| #include "stm32f4xx_hal_dma.h" |
| #include "stm32f4xx_hal_adc.h" |
| #include "stm32f4xx_hal_rcc.h" |
| #include "stm32f4xx_hal_cortex.h" |
| #include "stm32f4xx_hal.h" |
| #include "adc_stm32f4/adc_stm32f4.h" |
| #include "stm32f4xx_hal_dma.h" |
| #include "mcu/stm32f4xx_mynewt_hal.h" |
| |
| #if MYNEWT_VAL(ADC_1)||MYNEWT_VAL(ADC_2)||MYNEWT_VAL(ADC_3) |
| #include <adc/adc.h> |
| #endif |
| |
| #define STM32F4_IS_DMA_ADC_CHANNEL(CHANNEL) ((CHANNEL) <= DMA_CHANNEL_2) |
| |
| static DMA_HandleTypeDef *dma_handle[5]; |
| static struct adc_dev *adc_dma[5]; |
| |
| struct stm32f4_adc_stats { |
| uint16_t adc_events; |
| uint16_t adc_error; |
| uint16_t adc_dma_xfer_failed; |
| uint16_t adc_dma_xfer_aborted; |
| uint16_t adc_dma_xfer_complete; |
| uint16_t adc_dma_start_error; |
| uint16_t adc_dma_overrun; |
| uint16_t adc_internal_error; |
| }; |
| |
| static struct stm32f4_adc_stats stm32f4_adc_stats; |
| |
| static void |
| stm32f4_adc_clk_enable(ADC_HandleTypeDef *hadc) |
| { |
| uintptr_t adc_addr = (uintptr_t)hadc->Instance; |
| |
| switch (adc_addr) { |
| #if defined(ADC1) |
| case (uintptr_t)ADC1: |
| __HAL_RCC_ADC1_CLK_ENABLE(); |
| break; |
| #endif |
| #if defined(ADC2) |
| case (uintptr_t)ADC2: |
| __HAL_RCC_ADC2_CLK_ENABLE(); |
| break; |
| #endif |
| #if defined(ADC3) |
| case (uintptr_t)ADC3: |
| __HAL_RCC_ADC3_CLK_ENABLE(); |
| break; |
| #endif |
| default: |
| assert(0); |
| } |
| } |
| |
| static void |
| stm32f4_adc_clk_disable(ADC_HandleTypeDef *hadc) |
| { |
| uintptr_t adc_addr = (uintptr_t)hadc->Instance; |
| |
| switch (adc_addr) { |
| #if defined(ADC1) |
| case (uintptr_t)ADC1: |
| __HAL_RCC_ADC1_CLK_DISABLE(); |
| break; |
| #endif |
| #if defined(ADC2) |
| case (uintptr_t)ADC2: |
| __HAL_RCC_ADC2_CLK_DISABLE(); |
| break; |
| #endif |
| #if defined(ADC3) |
| case (uintptr_t)ADC3: |
| __HAL_RCC_ADC3_CLK_DISABLE(); |
| break; |
| #endif |
| default: |
| assert(0); |
| } |
| } |
| |
| static int |
| stm32f4_resolve_adc_gpio(ADC_HandleTypeDef *adc, uint8_t cnum, |
| GPIO_InitTypeDef *gpio) |
| { |
| uintptr_t adc_addr = (uintptr_t)adc->Instance; |
| uint32_t pin; |
| int rc; |
| |
| rc = OS_OK; |
| switch (adc_addr) { |
| #if defined(ADC1) || defined(ADC2) |
| #if defined(ADC1) |
| case (uintptr_t)ADC1: |
| #endif |
| #if defined(ADC2) |
| case (uintptr_t)ADC2: |
| #endif |
| switch(cnum) { |
| case ADC_CHANNEL_4: |
| pin = ADC12_CH4_PIN; |
| goto done; |
| case ADC_CHANNEL_5: |
| pin = ADC12_CH5_PIN; |
| goto done; |
| case ADC_CHANNEL_6: |
| pin = ADC12_CH6_PIN; |
| goto done; |
| case ADC_CHANNEL_7: |
| pin = ADC12_CH7_PIN; |
| goto done; |
| case ADC_CHANNEL_8: |
| pin = ADC12_CH8_PIN; |
| goto done; |
| case ADC_CHANNEL_9: |
| pin = ADC12_CH9_PIN; |
| goto done; |
| case ADC_CHANNEL_14: |
| pin = ADC12_CH14_PIN; |
| goto done; |
| case ADC_CHANNEL_15: |
| pin = ADC12_CH15_PIN; |
| goto done; |
| } |
| #endif |
| /* |
| * Falling through intentionally as ADC_3 contains seperate pins for |
| * Channels that ADC_1 and ADC_2 contain as well. |
| */ |
| #if defined(ADC3) |
| case (uintptr_t)ADC3: |
| switch(cnum) { |
| case ADC_CHANNEL_0: |
| pin = ADC123_CH0_PIN; |
| goto done; |
| case ADC_CHANNEL_1: |
| pin = ADC123_CH1_PIN; |
| goto done; |
| case ADC_CHANNEL_2: |
| pin = ADC123_CH2_PIN; |
| goto done; |
| case ADC_CHANNEL_3: |
| pin = ADC123_CH3_PIN; |
| goto done; |
| case ADC_CHANNEL_4: |
| pin = ADC3_CH4_PIN; |
| goto done; |
| case ADC_CHANNEL_5: |
| pin = ADC3_CH5_PIN; |
| goto done; |
| case ADC_CHANNEL_6: |
| pin = ADC3_CH6_PIN; |
| goto done; |
| case ADC_CHANNEL_7: |
| pin = ADC3_CH7_PIN; |
| goto done; |
| case ADC_CHANNEL_8: |
| pin = ADC3_CH8_PIN; |
| goto done; |
| case ADC_CHANNEL_9: |
| pin = ADC3_CH9_PIN; |
| goto done; |
| case ADC_CHANNEL_10: |
| pin = ADC123_CH10_PIN; |
| goto done; |
| case ADC_CHANNEL_11: |
| pin = ADC123_CH11_PIN; |
| goto done; |
| case ADC_CHANNEL_12: |
| pin = ADC123_CH12_PIN; |
| goto done; |
| case ADC_CHANNEL_13: |
| pin = ADC123_CH13_PIN; |
| goto done; |
| case ADC_CHANNEL_14: |
| pin = ADC3_CH14_PIN; |
| goto done; |
| case ADC_CHANNEL_15: |
| pin = ADC3_CH15_PIN; |
| goto done; |
| } |
| #endif |
| default: |
| rc = OS_EINVAL; |
| return rc; |
| } |
| done: |
| *gpio = (GPIO_InitTypeDef) { |
| .Pin = pin, |
| .Mode = GPIO_MODE_ANALOG, |
| .Pull = GPIO_NOPULL, |
| .Alternate = pin |
| }; |
| return rc; |
| } |
| |
| static IRQn_Type |
| stm32f4_resolve_adc_dma_irq(DMA_HandleTypeDef *hdma) |
| { |
| uintptr_t stream_addr = (uintptr_t)hdma->Instance; |
| |
| assert(STM32F4_IS_DMA_ADC_CHANNEL(hdma->Init.Channel)); |
| |
| switch(stream_addr) { |
| /* DMA2 */ |
| case (uintptr_t)DMA2_Stream0: |
| return DMA2_Stream0_IRQn; |
| case (uintptr_t)DMA2_Stream1: |
| return DMA2_Stream1_IRQn; |
| case (uintptr_t)DMA2_Stream2: |
| return DMA2_Stream2_IRQn; |
| case (uintptr_t)DMA2_Stream3: |
| return DMA2_Stream3_IRQn; |
| case (uintptr_t)DMA2_Stream4: |
| return DMA2_Stream4_IRQn; |
| default: |
| assert(0); |
| } |
| } |
| |
| static void |
| dma2_stream0_irq_handler(void) |
| { |
| HAL_DMA_IRQHandler(dma_handle[0]); |
| } |
| |
| static void |
| dma2_stream1_irq_handler(void) |
| { |
| HAL_DMA_IRQHandler(dma_handle[1]); |
| } |
| |
| static void |
| dma2_stream2_irq_handler(void) |
| { |
| HAL_DMA_IRQHandler(dma_handle[2]); |
| } |
| |
| static void |
| dma2_stream3_irq_handler(void) |
| { |
| HAL_DMA_IRQHandler(dma_handle[3]); |
| } |
| |
| static void |
| dma2_stream4_irq_handler(void) |
| { |
| HAL_DMA_IRQHandler(dma_handle[4]); |
| } |
| |
| uint32_t |
| stm32f4_resolve_adc_dma_irq_handler(DMA_HandleTypeDef *hdma) |
| { |
| switch((uintptr_t)hdma->Instance) { |
| /* DMA2 */ |
| case (uintptr_t)DMA2_Stream0: |
| return (uint32_t)&dma2_stream0_irq_handler; |
| case (uintptr_t)DMA2_Stream1: |
| return (uint32_t)&dma2_stream1_irq_handler; |
| case (uintptr_t)DMA2_Stream2: |
| return (uint32_t)&dma2_stream2_irq_handler; |
| case (uintptr_t)DMA2_Stream3: |
| return (uint32_t)&dma2_stream3_irq_handler; |
| case (uintptr_t)DMA2_Stream4: |
| return (uint32_t)&dma2_stream4_irq_handler; |
| default: |
| assert(0); |
| } |
| } |
| |
| static int |
| stm32f4_resolve_dma_handle_idx(DMA_HandleTypeDef *hdma) |
| { |
| uintptr_t stream_addr = (uintptr_t)hdma->Instance; |
| return ((stream_addr & 0xFF) - ((uintptr_t)DMA2_Stream0_BASE & 0xFF))/0x18; |
| } |
| |
| void |
| HAL_ADC_ErrorCallback(ADC_HandleTypeDef *hadc) |
| { |
| ++stm32f4_adc_stats.adc_error; |
| |
| if (hadc->ErrorCode & HAL_ADC_ERROR_DMA) { |
| /* DMA transfer error */ |
| ++stm32f4_adc_stats.adc_dma_xfer_failed; |
| } else if (hadc->ErrorCode & HAL_ADC_ERROR_OVR) { |
| /* DMA transfer overrun */ |
| ++stm32f4_adc_stats.adc_dma_overrun; |
| } else if (hadc->ErrorCode & HAL_ADC_ERROR_INTERNAL) { |
| /* ADC IP Internal Error */ |
| ++stm32f4_adc_stats.adc_internal_error; |
| } |
| } |
| |
| /** |
| * Callback that gets called by the HAL when ADC conversion is complete and |
| * the DMA buffer is full. If a secondary buffer exists it will the buffers. |
| * |
| * @param ADC Handle |
| */ |
| void |
| HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) |
| { |
| int rc; |
| struct adc_dev *adc; |
| DMA_HandleTypeDef *hdma; |
| struct stm32f4_adc_dev_cfg *cfg; |
| void *buf; |
| |
| assert(hadc); |
| hdma = hadc->DMA_Handle; |
| |
| ++stm32f4_adc_stats.adc_dma_xfer_complete; |
| |
| adc = adc_dma[stm32f4_resolve_dma_handle_idx(hdma)]; |
| cfg = (struct stm32f4_adc_dev_cfg *)adc->ad_dev.od_init_arg; |
| |
| buf = cfg->primarybuf; |
| /** |
| * If primary buffer gets full and secondary buffer exists, swap the |
| * buffers and start ADC conversion with DMA with the now primary |
| * buffer(former secondary buffer) |
| * If the secondary buffer(former primary buffer) doesn't get processed |
| * by the application in sampling period required for the primary/secondary buffer |
| * i,e; (sample itvl * ADC_NUMBER_SAMPLES), the buffers would get swapped resulting |
| * in new sample data. |
| */ |
| if (cfg->secondarybuf) { |
| cfg->primarybuf = cfg->secondarybuf; |
| cfg->secondarybuf = buf; |
| |
| if (HAL_ADC_Start_DMA(hadc, cfg->primarybuf, cfg->buflen) != HAL_OK) { |
| ++stm32f4_adc_stats.adc_dma_start_error; |
| } |
| } |
| |
| rc = adc->ad_event_handler_func(adc, NULL, ADC_EVENT_RESULT, buf, |
| cfg->buflen); |
| |
| if (rc) { |
| ++stm32f4_adc_stats.adc_error; |
| } |
| } |
| |
| static void |
| stm32f4_adc_dma_init(ADC_HandleTypeDef* hadc) |
| { |
| |
| DMA_HandleTypeDef *hdma; |
| |
| assert(hadc); |
| hdma = hadc->DMA_Handle; |
| |
| stm32f4_adc_clk_enable(hadc); |
| __HAL_RCC_DMA2_CLK_ENABLE(); |
| |
| HAL_DMA_Init(hdma); |
| dma_handle[stm32f4_resolve_dma_handle_idx(hdma)] = hdma; |
| |
| NVIC_SetPriority(stm32f4_resolve_adc_dma_irq(hdma), |
| NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0)); |
| NVIC_SetVector(stm32f4_resolve_adc_dma_irq(hdma), |
| stm32f4_resolve_adc_dma_irq_handler(hdma)); |
| NVIC_EnableIRQ(stm32f4_resolve_adc_dma_irq(hdma)); |
| |
| } |
| |
| static void |
| stm32f4_adc_init(struct adc_dev *dev) |
| { |
| struct stm32f4_adc_dev_cfg *adc_config; |
| ADC_HandleTypeDef *hadc; |
| |
| assert(dev); |
| |
| adc_config = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = adc_config->sac_adc_handle; |
| |
| stm32f4_adc_dma_init(hadc); |
| |
| if (HAL_ADC_Init(hadc) != HAL_OK) { |
| assert(0); |
| } |
| } |
| |
| static void |
| stm32f4_adc_uninit(struct adc_dev *dev) |
| { |
| GPIO_InitTypeDef gpio_td; |
| DMA_HandleTypeDef *hdma; |
| ADC_HandleTypeDef *hadc; |
| struct stm32f4_adc_dev_cfg *cfg; |
| uint8_t cnum; |
| |
| assert(dev); |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = cfg->sac_adc_handle; |
| hdma = hadc->DMA_Handle; |
| cnum = dev->ad_chans->c_cnum; |
| |
| __HAL_RCC_DMA2_CLK_DISABLE(); |
| if (HAL_DMA_DeInit(hdma) != HAL_OK) { |
| assert(0); |
| } |
| stm32f4_adc_clk_disable(hadc); |
| |
| NVIC_DisableIRQ(stm32f4_resolve_adc_dma_irq(hdma)); |
| |
| if (stm32f4_resolve_adc_gpio(hadc, cnum, &gpio_td)) { |
| goto err; |
| } |
| |
| if (hal_gpio_deinit_stm(gpio_td.Pin, &gpio_td)) { |
| goto err; |
| } |
| |
| err: |
| return; |
| } |
| |
| /** |
| * Open the STM32F4 ADC device |
| * |
| * This function locks the device for access from other tasks. |
| * |
| * @param odev The OS device to open |
| * @param wait The time in MS to wait. If 0 specified, returns immediately |
| * if resource unavailable. If OS_WAIT_FOREVER specified, blocks |
| * until resource is available. |
| * @param arg Argument provided by higher layer to open. |
| * |
| * @return 0 on success, non-zero on failure. |
| */ |
| static int |
| stm32f4_adc_open(struct os_dev *odev, uint32_t wait, void *arg) |
| { |
| DMA_HandleTypeDef *hdma; |
| ADC_HandleTypeDef *hadc; |
| struct stm32f4_adc_dev_cfg *cfg; |
| struct adc_dev *dev; |
| int rc; |
| |
| assert(odev); |
| rc = OS_OK; |
| dev = (struct adc_dev *) odev; |
| |
| if (os_started()) { |
| rc = os_mutex_pend(&dev->ad_lock, wait); |
| if (rc != OS_OK) { |
| goto err; |
| } |
| } |
| |
| if (odev->od_flags & OS_DEV_F_STATUS_OPEN) { |
| os_mutex_release(&dev->ad_lock); |
| rc = OS_EBUSY; |
| goto err; |
| } |
| |
| stm32f4_adc_init(dev); |
| |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = cfg->sac_adc_handle; |
| hdma = hadc->DMA_Handle; |
| |
| adc_dma[stm32f4_resolve_dma_handle_idx(hdma)] = dev; |
| |
| return (OS_OK); |
| err: |
| return (rc); |
| } |
| |
| |
| /** |
| * Close the STM32F4 ADC device. |
| * |
| * This function unlocks the device. |
| * |
| * @param odev The device to close. |
| */ |
| static int |
| stm32f4_adc_close(struct os_dev *odev) |
| { |
| struct adc_dev *dev; |
| |
| dev = (struct adc_dev *) odev; |
| |
| stm32f4_adc_uninit(dev); |
| |
| if (os_started()) { |
| os_mutex_release(&dev->ad_lock); |
| } |
| |
| return (OS_OK); |
| } |
| |
| /** |
| * Configure an ADC channel on the STM32F4 ADC. |
| * |
| * @param dev The ADC device to configure |
| * @param cnum The channel on the ADC device to configure |
| * @param cfgdata An opaque pointer to channel config, expected to be |
| * a ADC_ChannelConfTypeDef |
| * |
| * @return 0 on success, non-zero on failure. |
| */ |
| static int |
| stm32f4_adc_configure_channel(struct adc_dev *dev, uint8_t cnum, |
| void *cfgdata) |
| { |
| int rc; |
| ADC_HandleTypeDef *hadc; |
| struct stm32f4_adc_dev_cfg *cfg; |
| struct adc_chan_config *chan_cfg; |
| GPIO_InitTypeDef gpio_td; |
| |
| rc = OS_EINVAL; |
| |
| if (dev == NULL && !IS_ADC_CHANNEL(cnum)) { |
| goto err; |
| } |
| |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = cfg->sac_adc_handle; |
| chan_cfg = &((struct adc_chan_config *)cfg->sac_chans)[cnum]; |
| |
| cfgdata = (ADC_ChannelConfTypeDef *)cfgdata; |
| |
| if ((HAL_ADC_ConfigChannel(hadc, cfgdata)) != HAL_OK) { |
| goto err; |
| } |
| |
| dev->ad_chans[cnum].c_res = chan_cfg->c_res; |
| dev->ad_chans[cnum].c_refmv = chan_cfg->c_refmv; |
| dev->ad_chans[cnum].c_configured = 1; |
| dev->ad_chans[cnum].c_cnum = cnum; |
| |
| if (stm32f4_resolve_adc_gpio(hadc, cnum, &gpio_td)) { |
| goto err; |
| } |
| |
| hal_gpio_init_stm(gpio_td.Pin, &gpio_td); |
| |
| return (OS_OK); |
| err: |
| return (rc); |
| } |
| |
| /** |
| * Set buffer to read data into. Implementation of setbuffer handler. |
| * Sets both the primary and secondary buffers for DMA. |
| * |
| * For our current implementation we are using DMA in circular mode |
| * |
| */ |
| static int |
| stm32f4_adc_set_buffer(struct adc_dev *dev, void *buf1, void *buf2, |
| int buflen) |
| { |
| struct stm32f4_adc_dev_cfg *cfg; |
| int rc; |
| |
| |
| assert(dev != NULL && buf1 != NULL); |
| rc = OS_OK; |
| buflen /= sizeof(uint32_t); |
| |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| |
| cfg->primarybuf = buf1; |
| cfg->secondarybuf = buf2; |
| cfg->buflen = buflen; |
| |
| return rc; |
| } |
| |
| static int |
| stm32f4_adc_release_buffer(struct adc_dev *dev, void *buf, int buf_len) |
| { |
| ADC_HandleTypeDef *hadc; |
| struct stm32f4_adc_dev_cfg *cfg; |
| |
| assert(dev); |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = cfg->sac_adc_handle; |
| |
| HAL_ADC_Stop_DMA(hadc); |
| |
| return (0); |
| } |
| |
| /** |
| * Trigger an ADC sample. |
| * |
| * @param ADC device structure |
| * @return OS_OK on success, non OS_OK on failure |
| */ |
| static int |
| stm32f4_adc_sample(struct adc_dev *dev) |
| { |
| int rc; |
| ADC_HandleTypeDef *hadc; |
| struct stm32f4_adc_dev_cfg *cfg; |
| |
| assert(dev); |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = cfg->sac_adc_handle; |
| |
| rc = OS_EINVAL; |
| |
| if (HAL_ADC_Start_DMA(hadc, cfg->primarybuf, cfg->buflen) != HAL_OK) { |
| ++stm32f4_adc_stats.adc_dma_start_error; |
| goto err; |
| } |
| |
| rc = OS_OK; |
| |
| err: |
| return rc; |
| } |
| |
| /** |
| * Blocking read of an ADC channel, returns result as an integer. |
| * |
| * @param1 ADC device structure |
| * @param2 channel number |
| * @param3 ADC result ptr |
| */ |
| static int |
| stm32f4_adc_read_channel(struct adc_dev *dev, uint8_t cnum, int *result) |
| { |
| ADC_HandleTypeDef *hadc; |
| struct stm32f4_adc_dev_cfg *cfg; |
| |
| assert(dev != NULL && result != NULL); |
| cfg = (struct stm32f4_adc_dev_cfg *)dev->ad_dev.od_init_arg; |
| hadc = cfg->sac_adc_handle; |
| |
| *result = HAL_ADC_GetValue(hadc); |
| |
| return (OS_OK); |
| } |
| |
| static int |
| stm32f4_adc_read_buffer(struct adc_dev *dev, void *buf, int buf_len, int off, |
| int *result) |
| { |
| |
| assert(off < buf_len); |
| |
| /* |
| * If secondary buffer exists the primary buf is going to be cached |
| * in the secondary buffer if the primary buffer is full and we |
| * would be reading that instead since the buffer is specified by |
| * the application |
| */ |
| *result = *((uint32_t *)buf + off); |
| |
| return (OS_OK); |
| } |
| |
| /** |
| * Callback to return size of buffer |
| * |
| * @param1 ADC device ptr |
| * @param2 Total number of channels |
| * @param3 Total number of samples |
| * @return Length of buffer in bytes |
| */ |
| static int |
| stm32f4_adc_size_buffer(struct adc_dev *dev, int chans, int samples) |
| { |
| return (sizeof(uint32_t) * chans * samples); |
| } |
| |
| /** |
| * ADC device driver functions |
| */ |
| static const struct adc_driver_funcs stm32f4_adc_funcs = { |
| .af_configure_channel = stm32f4_adc_configure_channel, |
| .af_sample = stm32f4_adc_sample, |
| .af_read_channel = stm32f4_adc_read_channel, |
| .af_set_buffer = stm32f4_adc_set_buffer, |
| .af_release_buffer = stm32f4_adc_release_buffer, |
| .af_read_buffer = stm32f4_adc_read_buffer, |
| .af_size_buffer = stm32f4_adc_size_buffer, |
| }; |
| |
| /** |
| * Callback to initialize an adc_dev structure from the os device |
| * initialization callback. This sets up a stm32f4_adc_device(), so |
| * that subsequent lookups to this device allow us to manipulate it. |
| * |
| * @param1 os device ptr |
| * @param2 stm32f4 ADC device cfg ptr |
| * @return OS_OK on success |
| */ |
| int |
| stm32f4_adc_dev_init(struct os_dev *odev, void *arg) |
| { |
| struct stm32f4_adc_dev_cfg *sac; |
| struct adc_dev *dev; |
| |
| sac = (struct stm32f4_adc_dev_cfg *) arg; |
| |
| assert(sac != NULL); |
| |
| dev = (struct adc_dev *)odev; |
| |
| os_mutex_init(&dev->ad_lock); |
| |
| dev->ad_chans = (void *) sac->sac_chans; |
| dev->ad_chan_count = sac->sac_chan_count; |
| |
| OS_DEV_SETHANDLERS(odev, stm32f4_adc_open, stm32f4_adc_close); |
| |
| dev->ad_funcs = &stm32f4_adc_funcs; |
| |
| return (OS_OK); |
| } |
| |