/* include path: install_root/linux/include */ #include #include #include #include #include #include #include #include #include #include #include #include #include "stm32f4xx.h" #include "stm32f4xx_hal_rcc.h" #include "stm32f4xx_hal_gpio.h" #include "stm32f4xx_hal_adc.h" #include "stm32f4xx_hal_dma.h" #include "driver.h" #include "stm32_hal_legacy.h" static int major = MAJOR_ADC; static int minor = 0; //static dev_t devno; //static struct cdev *adc_cdev = NULL; //static int count = 3; #define NUM_OF_DEVICES 3 //ruct class *my_class = NULL; //struct device *dev = NULL; #define DEVNAME "adc" struct adc_device { dev_t devno; struct cdev cdev; char data[128]; char name[16]; IRQn_Type DMA_IRQn; } adc_dev[NUM_OF_DEVICES]; uint32_t gAdc1Value[10][4]; static int adc_open(struct inode *inode, struct file *filep); static int adc_close(struct inode *inode, struct file *filep); static ssize_t adc_read(struct file *filep, char __user *buf, size_t size, loff_t *offset); static ssize_t adc_write(struct file *filep, const char __user *buf, size_t size, loff_t *offset); static int adc_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg); static struct file_operations adc_ops = { .owner = THIS_MODULE, .open = adc_open, .release = adc_close, .read = adc_read, .write = adc_write, .ioctl = adc_ioctl, }; static int adc_open(struct inode *inode, struct file *filep) { int imajor,iminor; // ADC_HandleTypeDef hadc; imajor = MAJOR(inode->i_rdev); iminor = MINOR(inode->i_rdev); printk("adc open, major %d, minor %d\n", imajor, iminor); // if(imajor != MAJOR_ADC) // { // printk("Error: %s %d adc major fail! %d\n",__FILE__,__LINE__,imajor); // return -1; // } // switch(iminor) // { // case 0: // hadc.Instance = ADC1; // __HAL_RCC_ADC1_CLK_ENABLE(); // break; // case 1: // hadc.Instance = ADC2; // __HAL_RCC_ADC2_CLK_ENABLE(); // break; // case 2: // hadc.Instance = ADC3; // __HAL_RCC_ADC3_CLK_ENABLE(); // break; // } // __HAL_ADC_ENABLE(&hadc); return 0; } static int adc_close(struct inode *inode, struct file *filep) { int imajor,iminor; ADC_HandleTypeDef handle_adc; imajor = MAJOR(inode->i_rdev); iminor = MINOR(inode->i_rdev); if(imajor != MAJOR_ADC) { printk("Error: %s %d adc major fail! %d\n",__FILE__,__LINE__,imajor); return -1; } switch(iminor) { case 0: handle_adc.Instance = ADC1; __HAL_RCC_ADC1_CLK_DISABLE(); break; case 1: handle_adc.Instance = ADC2; __HAL_RCC_ADC1_CLK_DISABLE(); break; case 2: handle_adc.Instance = ADC3; __HAL_RCC_ADC1_CLK_DISABLE(); break; } printk("adc close, major %d, minor %d\n", imajor, iminor); __HAL_ADC_DISABLE(&handle_adc); return 0; } static ssize_t adc_read(struct file *filep, char __user *buf, size_t size, loff_t *offset) { //printk("fmc_read!\n"); return 0; } static ssize_t adc_write(struct file *filep, const char __user *buf, size_t size, loff_t *offset) { /* uint32_t i; uint8_t tmp_buf[100]; printk("fmc_write"); for(i=0;iStreamBaseAddress; tmpisr = regs->ISR; /* Transfer Error Interrupt management ***************************************/ if ((tmpisr & (DMA_FLAG_TEIF0_4 << hdma->StreamIndex)) != RESET) { if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TE) != RESET) { /* Disable the transfer error interrupt */ hdma->Instance->CR &= ~(DMA_IT_TE); /* Clear the transfer error flag */ regs->IFCR = DMA_FLAG_TEIF0_4 << hdma->StreamIndex; /* Update error code */ hdma->ErrorCode |= HAL_DMA_ERROR_TE; } } /* FIFO Error Interrupt management ******************************************/ if ((tmpisr & (DMA_FLAG_FEIF0_4 << hdma->StreamIndex)) != RESET) { if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_FE) != RESET) { /* Clear the FIFO error flag */ regs->IFCR = DMA_FLAG_FEIF0_4 << hdma->StreamIndex; /* Update error code */ hdma->ErrorCode |= HAL_DMA_ERROR_FE; } } /* Direct Mode Error Interrupt management ***********************************/ if ((tmpisr & (DMA_FLAG_DMEIF0_4 << hdma->StreamIndex)) != RESET) { if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_DME) != RESET) { /* Clear the direct mode error flag */ regs->IFCR = DMA_FLAG_DMEIF0_4 << hdma->StreamIndex; /* Update error code */ hdma->ErrorCode |= HAL_DMA_ERROR_DME; } } /* Half Transfer Complete Interrupt management ******************************/ if ((tmpisr & (DMA_FLAG_HTIF0_4 << hdma->StreamIndex)) != RESET) { if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_HT) != RESET) { /* Clear the half transfer complete flag */ regs->IFCR = DMA_FLAG_HTIF0_4 << hdma->StreamIndex; /* Multi_Buffering mode enabled */ if(((hdma->Instance->CR) & (uint32_t)(DMA_SxCR_DBM)) != RESET) { /* Current memory buffer used is Memory 0 */ if((hdma->Instance->CR & DMA_SxCR_CT) == RESET) { if(hdma->XferHalfCpltCallback != NULL) { /* Half transfer callback */ hdma->XferHalfCpltCallback(hdma); } } /* Current memory buffer used is Memory 1 */ else { if(hdma->XferM1HalfCpltCallback != NULL) { /* Half transfer callback */ hdma->XferM1HalfCpltCallback(hdma); } } } else { /* Disable the half transfer interrupt if the DMA mode is not CIRCULAR */ if((hdma->Instance->CR & DMA_SxCR_CIRC) == RESET) { /* Disable the half transfer interrupt */ hdma->Instance->CR &= ~(DMA_IT_HT); } if(hdma->XferHalfCpltCallback != NULL) { /* Half transfer callback */ hdma->XferHalfCpltCallback(hdma); } } } } /* Transfer Complete Interrupt management ***********************************/ if ((tmpisr & (DMA_FLAG_TCIF0_4 << hdma->StreamIndex)) != RESET) { if(__HAL_DMA_GET_IT_SOURCE(hdma, DMA_IT_TC) != RESET) { /* Clear the transfer complete flag */ regs->IFCR = DMA_FLAG_TCIF0_4 << hdma->StreamIndex; if(HAL_DMA_STATE_ABORT == hdma->State) { /* Disable all the transfer interrupts */ hdma->Instance->CR &= ~(DMA_IT_TC | DMA_IT_TE | DMA_IT_DME); hdma->Instance->FCR &= ~(DMA_IT_FE); if((hdma->XferHalfCpltCallback != NULL) || (hdma->XferM1HalfCpltCallback != NULL)) { hdma->Instance->CR &= ~(DMA_IT_HT); } /* Clear all interrupt flags at correct offset within the register */ regs->IFCR = 0x3FU << hdma->StreamIndex; /* Process Unlocked */ __HAL_UNLOCK(hdma); /* Change the DMA state */ hdma->State = HAL_DMA_STATE_READY; if(hdma->XferAbortCallback != NULL) { hdma->XferAbortCallback(hdma); } return IRQ_HANDLED; } if(((hdma->Instance->CR) & (uint32_t)(DMA_SxCR_DBM)) != RESET) { /* Current memory buffer used is Memory 0 */ if((hdma->Instance->CR & DMA_SxCR_CT) == RESET) { if(hdma->XferM1CpltCallback != NULL) { /* Transfer complete Callback for memory1 */ hdma->XferM1CpltCallback(hdma); } } /* Current memory buffer used is Memory 1 */ else { if(hdma->XferCpltCallback != NULL) { /* Transfer complete Callback for memory0 */ hdma->XferCpltCallback(hdma); } } } /* Disable the transfer complete interrupt if the DMA mode is not CIRCULAR */ else { if((hdma->Instance->CR & DMA_SxCR_CIRC) == RESET) { /* Disable the transfer complete interrupt */ hdma->Instance->CR &= ~(DMA_IT_TC); /* Process Unlocked */ __HAL_UNLOCK(hdma); /* Change the DMA state */ hdma->State = HAL_DMA_STATE_READY; } if(hdma->XferCpltCallback != NULL) { /* Transfer complete callback */ hdma->XferCpltCallback(hdma); } } } } /* manage error case */ if(hdma->ErrorCode != HAL_DMA_ERROR_NONE) { if((hdma->ErrorCode & HAL_DMA_ERROR_TE) != RESET) { hdma->State = HAL_DMA_STATE_ABORT; /* Disable the stream */ __HAL_DMA_DISABLE(hdma); do { if (++count > timeout) { break; } } while((hdma->Instance->CR & DMA_SxCR_EN) != RESET); /* Process Unlocked */ __HAL_UNLOCK(hdma); /* Change the DMA state */ hdma->State = HAL_DMA_STATE_READY; } if(hdma->XferErrorCallback != NULL) { /* Transfer error callback */ hdma->XferErrorCallback(hdma); } } return IRQ_HANDLED; } int adc_hw_init(void) { ADC_ChannelConfTypeDef sConfig; GPIO_InitTypeDef GPIO_InitStruct; /* ADC1 * PA3 - ADC1_IN3 * PA4 - ADC1_IN4 * PA5 - ADC1_IN5 * PA6 - ADC1_IN6 */ __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_ANALOG; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); hadc.Instance = ADC1; hadc.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.ScanConvMode = ENABLE; hadc.Init.ContinuousConvMode = ENABLE; hadc.Init.DiscontinuousConvMode = DISABLE; hadc.Init.NbrOfDiscConversion = 0; //hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc.Init.NbrOfConversion = 4; hadc.Init.DMAContinuousRequests = ENABLE; hadc.Init.EOCSelection = DISABLE; if(HAL_ADC_Init(&hadc) != HAL_OK) { printk(KERN_ERR"adc hw init error!\n"); } sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES; sConfig.Offset = 0; sConfig.Rank = 1; sConfig.Channel = ADC_CHANNEL_3; if(HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { printk(KERN_ERR"adc channel3 init error!\n"); } sConfig.Rank = 2; sConfig.Channel = ADC_CHANNEL_4; if(HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { printk(KERN_ERR"adc channel4 init error!\n"); } sConfig.Rank = 3; sConfig.Channel = ADC_CHANNEL_5; if(HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { printk(KERN_ERR"adc channel5 init error!\n"); } sConfig.Rank = 4; sConfig.Channel = ADC_CHANNEL_6; if(HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) { printk(KERN_ERR"adc channel6 init error!\n"); } __HAL_RCC_ADC1_CLK_ENABLE(); __HAL_ADC_ENABLE(&hadc); // config dma hdma_adc.Instance = DMA2_Stream0; hdma_adc.Init.Channel = DMA_CHANNEL_0; hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE; hdma_adc.Init.MemInc = DMA_MINC_ENABLE; hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_adc.Init.Mode = DMA_CIRCULAR; hdma_adc.Init.Priority = DMA_PRIORITY_HIGH; hdma_adc.Init.FIFOMode = DMA_FIFOMODE_DISABLE; hdma_adc.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL; hdma_adc.Init.MemBurst = DMA_MBURST_SINGLE; hdma_adc.Init.PeriphBurst = DMA_PBURST_SINGLE; HAL_DMA_Init(&hdma_adc); /* Associate the initialized DMA handle to the the ADC handle */ __HAL_LINKDMA(&hadc, DMA_Handle, hdma_adc); /*##-4- Configure the NVIC for DMA #########################################*/ /* NVIC configuration for DMA transfer complete interrupt */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 3, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); return 0; } static int __init adc_init(void) { int ret; int i; printk("adc driver init!\n"); for (i = 0; i < NUM_OF_DEVICES; i++) { adc_dev[i].devno = MKDEV(MAJOR_ADC, i); sprintf(adc_dev[i].name, "%s%d", DEVNAME, i+1); register_chrdev_region(adc_dev[i].devno, 1, adc_dev[i].name); cdev_add(&adc_dev[i].cdev, adc_dev[i].devno, 1); cdev_init(&adc_dev[i].cdev, &adc_ops); } if(adc_hw_init() != 0) goto ERR_STEP1; adc_dev[0].DMA_IRQn = DMA2_Stream0_IRQn; adc_dev[1].DMA_IRQn = DMA2_Stream2_IRQn; adc_dev[2].DMA_IRQn = DMA2_Stream1_IRQn; // register adc1 interrupt ret = request_irq(adc_dev[0].DMA_IRQn, HAL_DMA_IRQHandler, IRQF_SHARED, adc_dev[0].name, &adc_dev[0].devno); if(ret) { printk("request_irq() fialed! %d\n", ret); goto ERR_STEP1; } if(HAL_ADC_Start_DMA(&hadc, (uint32_t*)&gAdc1Value, 40) != HAL_OK) { printk("Start DMA error!"); } return 0; ERR_STEP1: unregister_chrdev_region(adc_dev[0].devno, NUM_OF_DEVICES); //ERR_STEP: cdev_del(&adc_dev[0].cdev); return 0; } static void __exit adc_exit(void) { unregister_chrdev_region(MKDEV(major, minor), NUM_OF_DEVICES); cdev_del(&adc_dev[0].cdev); } module_init(adc_init); module_exit(adc_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("jimbo_zhang"); MODULE_DESCRIPTION("adc driver");