1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2022-10-07     qiyu         first version
9  */
10 
11 #include <board.h>
12 #ifdef BSP_USING_ADC
13 #include "drv_config.h"
14 
15 #include "drv_adc.h"
16 #include "rtdbg.h"
17 
18 
19 static struct c28x_adc c28x_adc_obj[] =
20 {
21 #ifdef BSP_USING_ADC1
22     ADC1_CONFIG,
23 #endif
24 
25 #ifdef BSP_USING_ADC2
26     ADC2_CONFIG,
27 #endif
28 
29 #ifdef BSP_USING_ADC3
30     ADC3_CONFIG,
31 #endif
32 };
33 
34 
c28x_adc_enabled(struct rt_adc_device * device,rt_uint32_t channel,rt_bool_t enabled)35 static rt_err_t c28x_adc_enabled(struct rt_adc_device *device, rt_uint32_t channel, rt_bool_t enabled)
36 {
37     volatile struct ADC_REGS *c28x_adc_regs;
38     RT_ASSERT(device != RT_NULL);
39     volatile struct c28x_adc *c28x_adc_handler;
40     c28x_adc_handler = (struct c28x_adc *)device->parent.user_data;
41     c28x_adc_regs = c28x_adc_handler->adc_regs;
42 
43     if (enabled)
44     {
45         /*
46          * power up the ADC
47          */
48         EALLOW;
49         c28x_adc_regs->ADCCTL1.bit.ADCPWDNZ = 1;
50         EDIS;
51         /*
52          * delay for 1ms to allow ADC time to power up
53          */
54         DELAY_US(1000);
55     }
56     else
57     {
58         /*
59          * power down the ADC
60          */
61         EALLOW;
62         c28x_adc_regs->ADCCTL1.bit.ADCPWDNZ = 0;
63         EDIS;
64     }
65 
66     return RT_EOK;
67 }
68 
c28x_adc_get_resolution(struct rt_adc_device * device)69 static rt_uint8_t c28x_adc_get_resolution(struct rt_adc_device *device)
70 {
71     struct c28x_adc *c28x_adc_handler;
72     volatile struct ADC_REGS *c28x_adc_regs;
73     c28x_adc_handler = (struct c28x_adc *)device->parent.user_data;
74     c28x_adc_regs = c28x_adc_handler->adc_regs;
75     RT_ASSERT(device != RT_NULL);
76     switch(c28x_adc_regs->ADCCTL2.bit.RESOLUTION)
77     {
78         case ADC_RESOLUTION_12BIT:
79             return 12;
80         case ADC_RESOLUTION_16BIT:
81             return 16;
82         default:
83             return 0;
84     }
85 }
86 
c28x_adc_get_vref(struct rt_adc_device * device)87 static rt_int16_t c28x_adc_get_vref (struct rt_adc_device *device)
88 {
89     /*
90      * TODO
91      * Get Vref
92      */
93     RT_ASSERT(device);
94     return 3300;
95 }
96 
c28x_adc_get_value(struct rt_adc_device * device,rt_uint32_t channel,rt_uint32_t * value)97 static rt_err_t c28x_adc_get_value(struct rt_adc_device *device, rt_uint32_t channel, rt_uint32_t *value)
98 {
99     RT_ASSERT(device != RT_NULL);
100     RT_ASSERT(value != RT_NULL);
101 
102     struct c28x_adc *c28x_adc_handler = (struct c28x_adc*)device->parent.user_data;
103     volatile struct ADC_REGS *c28x_adc_regs = c28x_adc_handler->adc_regs;
104     volatile struct ADC_RESULT_REGS *c28x_adc_result_regs = c28x_adc_handler->adc_results;
105 
106     /*
107      * configure channel
108      * only use SOC0 for now
109      */
110     EALLOW;
111     c28x_adc_regs->ADCSOC0CTL.bit.CHSEL = channel;  /* SOC0 will convert pin A0 */
112     EDIS;
113     /*
114      * start conversions immediately via software, ADCA
115      */
116     c28x_adc_regs->ADCSOCFRC1.all = 0x0001; //SOC0
117     /*
118      * wait for ADCA to complete, then acknowledge flag
119      */
120     while(c28x_adc_regs->ADCINTFLG.bit.ADCINT1 == 0);
121     c28x_adc_regs->ADCINTFLGCLR.bit.ADCINT1 = 1;
122 
123     /*
124      * store results
125      */
126     *value = (rt_uint32_t)c28x_adc_result_regs->ADCRESULT0;
127 
128     return RT_EOK;
129 }
130 
131 static const struct rt_adc_ops stm_adc_ops =
132 {
133     .enabled = c28x_adc_enabled,
134     .convert = c28x_adc_get_value,
135     .get_resolution = c28x_adc_get_resolution,
136     .get_vref = c28x_adc_get_vref,
137 };
138 
HAL_ADC_Init(volatile struct ADC_REGS * c28x_adc_handler)139 static rt_err_t HAL_ADC_Init(volatile struct ADC_REGS *c28x_adc_handler)
140 {
141     int adc_controller_num = 0;
142     Uint16 acqps;
143 
144     EALLOW;
145     /*
146      * write configurations
147      */
148     c28x_adc_handler->ADCCTL2.bit.PRESCALE = 6; //set ADCCLK divider to /4
149     if(c28x_adc_handler == &AdcaRegs)
150     {
151         adc_controller_num = 0;
152     }else if(c28x_adc_handler == &AdcbRegs)
153     {
154         adc_controller_num = 1;
155     }
156     else if(c28x_adc_handler == &AdccRegs)
157     {
158         adc_controller_num = 2;
159     }
160     else if(c28x_adc_handler == &AdcdRegs)
161     {
162         adc_controller_num = 3;
163     }
164     AdcSetMode(adc_controller_num, ADC_RESOLUTION, ADC_SIGNALMODE_SINGLE);
165     c28x_adc_handler->ADCCTL1.bit.INTPULSEPOS = 1;
166     EDIS;
167 
168     /*
169      * determine minimum acquisition window (in SYSCLKS) based on resolution
170      */
171     if(ADC_RESOLUTION_12BIT == AdcaRegs.ADCCTL2.bit.RESOLUTION)
172     {
173         acqps = 14; //75ns
174     }
175     else
176     {
177         /*
178          * resolution is 16-bit
179          */
180         acqps = 63; //320ns
181     }
182 
183     /*
184      * Select the channels to convert and end of conversion flag
185      */
186     EALLOW;
187     c28x_adc_handler->ADCSOC0CTL.bit.ACQPS = acqps; //sample window is acqps + 1 SYSCLK cycles
188     c28x_adc_handler->ADCINTSEL1N2.bit.INT1SEL = 0; //end of SOC0 will set INT1 flag
189     c28x_adc_handler->ADCINTSEL1N2.bit.INT1E = 1;   //enable INT1 flag
190     c28x_adc_handler->ADCINTFLGCLR.bit.ADCINT1 = 1; //make sure INT1 flag is cleared
191     EDIS;
192     return RT_EOK;
193 }
194 
c28x_adc_init(void)195 static int c28x_adc_init(void)
196 {
197     int result = RT_EOK;
198     /*
199      * save adc name
200      */
201     int i = 0;
202     /* ADC init */
203     for (i = 0; i < sizeof(c28x_adc_obj) / sizeof(c28x_adc_obj[0]); i++)
204     {
205         if (HAL_ADC_Init(c28x_adc_obj[i].adc_regs) != RT_EOK)
206         {
207             LOG_E("%s init failed", c28x_adc_obj[i].name);
208             result = -RT_ERROR;
209         }
210         else
211         {
212             /* register ADC device */
213             if (rt_hw_adc_register(&c28x_adc_obj[i].c28x_adc_device, c28x_adc_obj[i].name, &stm_adc_ops, &c28x_adc_obj[i]) == RT_EOK)
214             {
215                 LOG_D("%s init success", c28x_adc_obj[i].name);
216             }
217             else
218             {
219                 LOG_E("%s register failed", c28x_adc_obj[i].name);
220                 result = -RT_ERROR;
221             }
222         }
223     }
224 
225     return result;
226 }
227 INIT_BOARD_EXPORT(c28x_adc_init);
228 
229 #endif /* BSP_USING_ADC */
230