Skip to content

Commit 179098d

Browse files
authored
Merge pull request #8828 from OpenNuvoton/nuvoton_analogout
Nuvoton: Support DAC HAL
2 parents 3cc7530 + e24a3c0 commit 179098d

21 files changed

+831
-0
lines changed

targets/TARGET_NUVOTON/TARGET_M2351/PeripheralNames.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,16 @@ typedef enum {
124124

125125
} ADCName;
126126

127+
typedef enum {
128+
#if defined(SCU_INIT_PNSSET2_VAL) && (SCU_INIT_PNSSET2_VAL & (1 << 7))
129+
DAC_0_0 = (int) NU_MODNAME(DAC0_BASE + NS_OFFSET, 0, 0),
130+
DAC_1_0 = (int) NU_MODNAME(DAC1_BASE + NS_OFFSET, 1, 0)
131+
#else
132+
DAC_0_0 = (int) NU_MODNAME(DAC0_BASE, 0, 0),
133+
DAC_1_0 = (int) NU_MODNAME(DAC1_BASE, 1, 0)
134+
#endif
135+
} DACName;
136+
127137
typedef enum {
128138

129139
#if defined(SCU_INIT_PNSSET3_VAL) && (SCU_INIT_PNSSET3_VAL & (1<<16))

targets/TARGET_NUVOTON/TARGET_M2351/PeripheralPins.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,15 @@ const PinMap PinMap_ADC[] = {
172172
{NC, NC, 0}
173173
};
174174

175+
//*** DAC ***
176+
177+
const PinMap PinMap_DAC[] = {
178+
{PB_12, DAC_0_0, SYS_GPB_MFPH_PB12MFP_DAC0_OUT},
179+
{PB_13, DAC_1_0, SYS_GPB_MFPH_PB13MFP_DAC1_OUT},
180+
181+
{NC, NC, 0}
182+
};
183+
175184
//*** I2C ***
176185

177186
const PinMap PinMap_I2C_SDA[] = {

targets/TARGET_NUVOTON/TARGET_M2351/PeripheralPins.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ extern const PinMap PinMap_GPIO[];
3232

3333
extern const PinMap PinMap_ADC[];
3434

35+
//*** DAC ***
36+
37+
extern const PinMap PinMap_DAC[];
38+
3539
//*** I2C ***
3640

3741
extern const PinMap PinMap_I2C_SDA[];
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
* Copyright (c) 2018, Nuvoton Technology Corporation
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "analogout_api.h"
19+
20+
#if DEVICE_ANALOGOUT
21+
22+
#include "cmsis.h"
23+
#include "pinmap.h"
24+
#include "PeripheralPins.h"
25+
#include "nu_modutil.h"
26+
27+
/* Maximum DAC modules */
28+
#define NU_DACMOD_MAXNUM 2
29+
/* Maximum DAC channels per module */
30+
#define NU_DACCHN_MAXNUM 1
31+
32+
static uint32_t dac_modinit_mask[NU_DACMOD_MAXNUM];
33+
34+
static const struct nu_modinit_s dac_modinit_tab[] = {
35+
{DAC_0_0, DAC_MODULE, 0, 0, DAC_RST, DAC_IRQn, NULL},
36+
{DAC_1_0, DAC_MODULE, 0, 0, DAC_RST, DAC_IRQn, NULL}
37+
};
38+
39+
void analogout_init(dac_t *obj, PinName pin)
40+
{
41+
obj->dac = (DACName) pinmap_peripheral(pin, PinMap_DAC);
42+
MBED_ASSERT(obj->dac != (DACName) NC);
43+
44+
const struct nu_modinit_s *modinit = get_modinit(obj->dac, dac_modinit_tab);
45+
MBED_ASSERT(modinit != NULL);
46+
MBED_ASSERT(modinit->modname == obj->dac);
47+
48+
/* Module index */
49+
uint32_t modidx = NU_MODINDEX(obj->dac);
50+
MBED_ASSERT(modidx < NU_DACMOD_MAXNUM);
51+
52+
/* Module subindex (aka channel) */
53+
uint32_t chn = NU_MODSUBINDEX(obj->dac);
54+
MBED_ASSERT(chn < NU_DACCHN_MAXNUM);
55+
56+
DAC_T *dac_base = (DAC_T *) NU_MODBASE(obj->dac);
57+
58+
/* Module-level setup from here */
59+
60+
/* DAC0/DAC1 are designed to share the same RESET/clock/IRQ for group
61+
* function. So we:
62+
*
63+
* 1. Go to setup flow (analogout_init()) only when none of DAC0/DAC1
64+
* channels are activated.
65+
* 2. Go to windup flow (analogout_free()) only when all DAC0/DAC1
66+
* channels are deactivated.
67+
*/
68+
if ((! dac_modinit_mask[0]) && (! dac_modinit_mask[1])) {
69+
/* Reset IP
70+
*
71+
* NOTE: We must call secure version (from non-secure domain) because SYS/CLK regions are secure.
72+
*/
73+
SYS_ResetModule_S(modinit->rsetidx);
74+
75+
/* Select IP clock source and clock divider
76+
*
77+
* NOTE: We must call secure version (from non-secure domain) because SYS/CLK regions are secure.
78+
*/
79+
CLK_SetModuleClock_S(modinit->clkidx, modinit->clksrc, modinit->clkdiv);
80+
81+
/* Enable IP clock
82+
*
83+
* NOTE: We must call secure version (from non-secure domain) because SYS/CLK regions are secure.
84+
*/
85+
CLK_EnableModuleClock_S(modinit->clkidx);
86+
87+
/* The conversion settling time is 8us when 12-bit input code transition from
88+
* lowest code (0x000) to highest code (0xFFF). */
89+
DAC_SetDelayTime(dac_base, 8);
90+
91+
/* Configure DAT data format to left-aligned
92+
* Effective 12-bits are aligned to left of 16-bit DAC_DAT. */
93+
DAC_ENABLE_LEFT_ALIGN(dac_base);
94+
}
95+
96+
/* Channel-level setup from here: */
97+
98+
/* Set the software trigger, enable DAC event trigger mode and enable D/A converter */
99+
DAC_Open(dac_base, chn, DAC_SOFTWARE_TRIGGER);
100+
101+
/* Wire pinout */
102+
pinmap_pinout(pin, PinMap_DAC);
103+
104+
/* Mark channel allocated */
105+
dac_modinit_mask[modidx] |= 1 << chn;
106+
}
107+
108+
void analogout_free(dac_t *obj)
109+
{
110+
const struct nu_modinit_s *modinit = get_modinit(obj->dac, dac_modinit_tab);
111+
MBED_ASSERT(modinit != NULL);
112+
MBED_ASSERT(modinit->modname == obj->dac);
113+
114+
/* Module index */
115+
uint32_t modidx = NU_MODINDEX(obj->dac);
116+
MBED_ASSERT(modidx < NU_DACMOD_MAXNUM);
117+
118+
/* Module subindex (aka channel) */
119+
uint32_t chn = NU_MODSUBINDEX(obj->dac);
120+
MBED_ASSERT(chn < NU_DACCHN_MAXNUM);
121+
122+
DAC_T *dac_base = (DAC_T *) NU_MODBASE(obj->dac);
123+
124+
/* Channel-level windup from here */
125+
126+
/* Mark channel free */
127+
dac_modinit_mask[modidx] &= ~(1 << modidx);
128+
129+
/* Close channel */
130+
DAC_Close(dac_base, chn);
131+
132+
/* Module-level windup from here: */
133+
134+
/* See analogout_init() for reason */
135+
if ((! dac_modinit_mask[0]) && (! dac_modinit_mask[1])) {
136+
137+
/* Disable IP clock
138+
*
139+
* NOTE: We must call secure version (from non-secure domain) because SYS/CLK regions are secure.
140+
*/
141+
CLK_DisableModuleClock_S(modinit->clkidx);
142+
}
143+
}
144+
145+
void analogout_write(dac_t *obj, float value)
146+
{
147+
if (value <= 0.0f) {
148+
analogout_write_u16(obj, 0);
149+
} else if (value >= 1.0f) {
150+
analogout_write_u16(obj, 0xFFFF);
151+
} else {
152+
analogout_write_u16(obj, (uint16_t) (value * ((float) 0xFFFF)));
153+
}
154+
}
155+
156+
void analogout_write_u16(dac_t *obj, uint16_t value)
157+
{
158+
DAC_T *dac_base = (DAC_T *) NU_MODBASE(obj->dac);
159+
uint32_t chn = NU_MODSUBINDEX(obj->dac);
160+
161+
/* We should have configured DAC data format to left-aligned */
162+
MBED_ASSERT(dac_base->CTL & DAC_CTL_LALIGN_Msk);
163+
DAC_WRITE_DATA(dac_base, chn, value);
164+
165+
/* Clear the DAC conversion complete finish flag for safe */
166+
DAC_CLR_INT_FLAG(dac_base, chn);
167+
168+
/* Start A/D conversion */
169+
DAC_START_CONV(dac_base);
170+
171+
/* Wait for completed */
172+
while (DAC_IS_BUSY(dac_base, chn));
173+
}
174+
175+
float analogout_read(dac_t *obj)
176+
{
177+
uint32_t value = analogout_read_u16(obj);
178+
return (float) value * (1.0f / (float) 0xFFFF);
179+
}
180+
181+
uint16_t analogout_read_u16(dac_t *obj)
182+
{
183+
DAC_T *dac_base = (DAC_T *) NU_MODBASE(obj->dac);
184+
uint32_t chn = NU_MODSUBINDEX(obj->dac);
185+
186+
/* We should have configured DAC data format to left-aligned */
187+
MBED_ASSERT(dac_base->CTL & DAC_CTL_LALIGN_Msk);
188+
uint16_t dat12_4 = DAC_READ_DATA(dac_base, chn);
189+
/* Just 12 bits are effective. Convert to 16 bits.
190+
*
191+
* dat12_4 : b11b10b9b8 b7b6b5b4 b3b2b1b0 0000
192+
* dat16 : b11b10b9b8 b7b6b5b4 b3b2b1b0 b11b10b9b8
193+
*/
194+
uint16_t dat16 = (dat12_4 & 0xFFF0) | (dat12_4 >> 12);
195+
196+
return dat16;
197+
}
198+
199+
#endif

targets/TARGET_NUVOTON/TARGET_M2351/objects.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ struct analogin_s {
4444
ADCName adc;
4545
};
4646

47+
struct dac_s {
48+
DACName dac;
49+
};
50+
4751
struct serial_s {
4852
UARTName uart;
4953
PinName pin_tx;

targets/TARGET_NUVOTON/TARGET_M451/PeripheralNames.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ typedef enum {
6565
ADC_0_15 = (int) NU_MODNAME(EADC0_BASE, 0, 15)
6666
} ADCName;
6767

68+
typedef enum {
69+
DAC_0_0 = (int) NU_MODNAME(DAC_BASE, 0, 0)
70+
} DACName;
71+
6872
typedef enum {
6973
UART_0 = (int) NU_MODNAME(UART0_BASE, 0, 0),
7074
UART_1 = (int) NU_MODNAME(UART1_BASE, 1, 0),

targets/TARGET_NUVOTON/TARGET_M451/PeripheralPins.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,14 @@ const PinMap PinMap_ADC[] = {
158158
{NC, NC, 0}
159159
};
160160

161+
//*** DAC ***
162+
163+
const PinMap PinMap_DAC[] = {
164+
{PB_0, DAC_0_0, SYS_GPB_MFPL_PB0MFP_DAC},
165+
166+
{NC, NC, 0}
167+
};
168+
161169
//*** I2C ***
162170

163171
const PinMap PinMap_I2C_SDA[] = {

targets/TARGET_NUVOTON/TARGET_M451/PeripheralPins.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ extern const PinMap PinMap_GPIO[];
3232

3333
extern const PinMap PinMap_ADC[];
3434

35+
//*** DAC ***
36+
37+
extern const PinMap PinMap_DAC[];
38+
3539
//*** I2C ***
3640

3741
extern const PinMap PinMap_I2C_SDA[];

0 commit comments

Comments
 (0)