1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2017-12-04     Haley        the first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "am_mcu_apollo.h"
14 
15 #ifdef RT_USING_PDM
16 
17 /* messagequeue define */
18 struct rt_messagequeue pdm_mq;
19 
20 static rt_uint8_t am_pdm_buffer_pool[1024];
21 
22 #define NWA_FRAME_SAMPLES   160    /* 8k, 16bit, mono audio data */
23 #define PDM_FIFO_THRESHOLD  NWA_FRAME_SAMPLES
24 
25 #define PDM_GPIO_CLK        22
26 #define PDM_GPIO_CFG_CLK    AM_HAL_PIN_22_PDM_CLK
27 #define PDM_GPIO_DATA       23
28 #define PDM_GPIO_CFG_DATA   AM_HAL_PIN_23_PDM_DATA
29 
30 static am_hal_pdm_config_t g_sPDMConfig =
31 {
32     AM_HAL_PDM_PCFG_LRSWAP_DISABLE | AM_HAL_PDM_PCFG_RIGHT_PGA_0DB | AM_HAL_PDM_PCFG_LEFT_PGA_0DB
33             | AM_HAL_PDM_PCFG_MCLKDIV_DIV1 | AM_HAL_PDM_PCFG_SINC_RATE(48) | AM_HAL_PDM_PCFG_ADCHPD_ENABLE
34             | AM_HAL_PDM_PCFG_HPCUTOFF(0x1) | AM_HAL_PDM_PCFG_CYCLES(0x1) | AM_HAL_PDM_PCFG_SOFTMUTE_DISABLE
35             | AM_HAL_PDM_PCFG_PDMCORE_ENABLE, /* Set the PDM configuration */
36     AM_HAL_PDM_IOCLK_750KHZ | AM_HAL_PDM_VCFG_RSTB_NORMAL | AM_HAL_PDM_VCFG_PDMCLK_ENABLE
37             | AM_HAL_PDM_VCFG_I2SMODE_DISABLE | AM_HAL_PDM_VCFG_BCLKINV_DISABLE | AM_HAL_PDM_VCFG_DMICDEL_DISABLE
38             | AM_HAL_PDM_VCFG_SELAP_INTERNAL | AM_HAL_PDM_VCFG_PACK_DISABLE | AM_HAL_PDM_VCFG_CHANNEL_LEFT, /* Set the Voice Configuration */
39     PDM_FIFO_THRESHOLD, /* Select the FIFO PCM sample threshold 0~256 */
40 };
41 
42 /**
43  * @brief Get the pdm data.
44  *
45  * @param None.
46  *
47  * This function Get the pdm data.
48  *
49  * @return None.
50  */
am_pdm_data_get(rt_uint8_t * buff,rt_uint16_t size)51 rt_uint8_t am_pdm_data_get(rt_uint8_t *buff, rt_uint16_t size)
52 {
53     rt_uint8_t pdm_rbufftemp[340];
54 
55     /* wait pdm message forever */
56     rt_mq_recv(&pdm_mq, pdm_rbufftemp, 340, RT_WAITING_FOREVER);
57 
58     /* copy the data */
59     rt_memcpy(buff, (char *)pdm_rbufftemp, size);
60 
61     return 0;
62 }
63 
64 /**
65  * @brief Start the pdm.
66  *
67  * @param None.
68  *
69  * This function Start the pdm.
70  *
71  * @return None.
72  */
am_pdm_start(void)73 void am_pdm_start(void)
74 {
75     /* Enable PDM */
76     am_hal_interrupt_enable(AM_HAL_INTERRUPT_PDM);
77     am_hal_pdm_enable();
78 }
79 
80 /**
81  * @brief Stop the pdm.
82  *
83  * @param None.
84  *
85  * This function Stop the pdm.
86  *
87  * @return None.
88  */
am_pdm_stop(void)89 void am_pdm_stop(void)
90 {
91     /* Disable PDM */
92     am_hal_interrupt_disable(AM_HAL_INTERRUPT_PDM);
93     am_hal_pdm_disable();
94 }
95 
96 /**
97  * @brief Get the pdm left gain.
98  *
99  * @param None.
100  *
101  * This function Get the pdm left gain.
102  *
103  * @return gain_val.
104  */
am_pdm_left_gain_get(void)105 uint8_t am_pdm_left_gain_get(void)
106 {
107     /* get the left gain */
108     return am_hal_pdm_left_gain_get();
109 }
110 
111 /**
112  * @brief Set the pdm left gain.
113  *
114  * @param gain_val.
115  *
116  * This function Set the pdm left gain.
117  *
118  * @return None.
119  */
am_pdm_left_gain_set(uint8_t gain_val)120 void am_pdm_left_gain_set(uint8_t gain_val)
121 {
122     /* set the left gain */
123     am_hal_pdm_left_gain_set(gain_val);
124 }
125 
126 /**
127  * @brief Get the pdm right gain.
128  *
129  * @param None.
130  *
131  * This function Get the pdm right gain.
132  *
133  * @return gain_val.
134  */
am_pdm_right_gain_get(void)135 uint8_t am_pdm_right_gain_get(void)
136 {
137     /* get the right gain */
138     return am_hal_pdm_right_gain_get();
139 }
140 
141 /**
142  * @brief Set the pdm right gain.
143  *
144  * @param gain_val.
145  *
146  * This function Set the pdm right gain.
147  *
148  * @return None.
149  */
am_pdm_right_gain_set(uint8_t gain_val)150 void am_pdm_right_gain_set(uint8_t gain_val)
151 {
152     /* set the right gain */
153     am_hal_pdm_right_gain_set(gain_val);
154 }
155 
156 /**
157  * @brief Interrupt handler for the PDM
158  *
159  * This function is Interrupt handler for the PDM
160  *
161  * @return None.
162  */
am_pdm_isr(void)163 void am_pdm_isr (void)
164 {
165     int i;
166     rt_int16_t pdm_sbufftemp[160];
167 
168     /* Clear the PDM interrupt */
169     am_hal_pdm_int_clear(AM_HAL_PDM_INT_UNDFL | AM_HAL_PDM_INT_OVF | AM_HAL_PDM_INT_FIFO);
170 
171     for (i = 0; i < PDM_FIFO_THRESHOLD; i++)  /* adjust as needed */
172     {
173         pdm_sbufftemp[i] = (rt_int16_t)am_hal_pdm_fifo_data_read();
174     }
175 
176     /* send the message */
177     rt_mq_send(&pdm_mq, pdm_sbufftemp, PDM_FIFO_THRESHOLD*sizeof(rt_int16_t));
178 }
179 
180 /**
181  * @brief Initialize the PDM
182  *
183  * This function initialize the PDM
184  *
185  * @return None.
186  */
rt_hw_pdm_init(void)187 int rt_hw_pdm_init(void)
188 {
189     /* Enable power to modules used */
190     am_hal_pwrctrl_periph_enable(AM_HAL_PWRCTRL_PDM);
191 
192     /* Enable the PDM clock and data */
193     am_hal_gpio_pin_config(PDM_GPIO_CLK, PDM_GPIO_CFG_CLK | AM_HAL_GPIO_HIGH_DRIVE);
194     am_hal_gpio_pin_config(PDM_GPIO_DATA, PDM_GPIO_CFG_DATA );
195 
196     /* PDM setting */
197     am_hal_pdm_config(&g_sPDMConfig);
198 
199     /* Enable PDM interrupts */
200     am_hal_pdm_int_enable(AM_HAL_PDM_INT_FIFO);
201 
202     /* Clear PDM interrupts */
203     am_hal_pdm_int_clear(AM_HAL_PDM_INT_UNDFL | AM_HAL_PDM_INT_OVF | AM_HAL_PDM_INT_FIFO);
204 
205     /* messagequeue init */
206     rt_mq_init(&pdm_mq, "mq_pdm",
207             &am_pdm_buffer_pool[0],
208             340 - sizeof(void*),
209             sizeof(am_pdm_buffer_pool),
210             RT_IPC_FLAG_FIFO);
211 
212     //rt_kprintf("pdm_init!\n");
213 
214     return 0;
215 }
216 #ifdef RT_USING_COMPONENTS_INIT
217 INIT_BOARD_EXPORT(rt_hw_pdm_init);
218 #endif
219 
220 #endif
221 
222 /*@}*/
223