1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author        Notes
8  * 2023-02-14     Rbb666        first version
9  */
10 #include <rtthread.h>
11 #include "hal_data.h"
12 #include <rtdevice.h>
13 #include <rthw.h>
14 
15 #include "pwm_audio.h"
16 
17 #define BUFFER_MIN_SIZE     (256UL)
18 #define SAMPLE_RATE_MAX     (48000)
19 #define SAMPLE_RATE_MIN     (8000)
20 #define CHANNEL_LEFT_INDEX  (0)
21 #define CHANNEL_RIGHT_INDEX (1)
22 #define CHANNEL_LEFT_MASK   (0x01)
23 #define CHANNEL_RIGHT_MASK  (0x02)
24 #define VOLUME_0DB          (16)
25 
26 typedef struct
27 {
28     char *buf;                         /**< Original pointer */
29     uint32_t volatile head;            /**< ending pointer */
30     uint32_t volatile tail;            /**< Read pointer */
31     uint32_t size;                     /**< Buffer size */
32     uint32_t is_give;                  /**< semaphore give flag */
33     rt_sem_t semaphore_rb;             /**< Semaphore for ringbuffer */
34 
35 } ringBuf;
36 typedef ringBuf *ringbuf_handle_t;
37 
38 typedef struct
39 {
40     pwm_audio_config_t    config;                          /**< pwm audio config struct */
41     timer_cfg_t           pwm_timer_cfg;                   /**< ledc timer config  */
42     timer_cfg_t           gen_timer_cfg;                   /**< general timer config  */
43     gpt_instance_ctrl_t   *pwm_timer_ctrl;                 /**< timer group register pointer */
44     gpt_instance_ctrl_t   *gen_timer_ctrl;                 /**< timer group register pointer */
45     ringbuf_handle_t      ringbuf;                         /**< audio ringbuffer pointer */
46     uint32_t              channel_mask;                    /**< channel gpio mask */
47     uint32_t              channel_set_num;                 /**< channel audio set number */
48     int32_t               framerate;                       /*!< frame rates in Hz */
49     int32_t               bits_per_sample;                 /*!< bits per sample (8, 16, 32) */
50     int32_t               volume;                          /*!< the volume(-VOLUME_0DB ~ VOLUME_0DB) */
51     rt_sem_t              sem_complete;                    /**< Semaphore for play complete */
52 
53     pwm_audio_status_t status;
54 } pwm_audio_handle;
55 typedef pwm_audio_handle *pwm_audio_handle_t;
56 
57 /**< pwm audio handle pointer */
58 static pwm_audio_handle_t g_pwm_audio_handle = NULL;
59 
60 /**
61  * Ringbuffer for pwm audio
62  */
rb_destroy(ringbuf_handle_t rb)63 static rt_err_t rb_destroy(ringbuf_handle_t rb)
64 {
65     if (rb == NULL)
66     {
67         return RT_ERROR;
68     }
69 
70     if (rb->buf)
71     {
72         rt_free(rb->buf);
73         rb->buf = NULL;
74     }
75 
76     if (rb->semaphore_rb)
77     {
78         rt_sem_delete(rb->semaphore_rb);
79     }
80 
81     rt_free(rb);
82     return RT_EOK;
83 }
84 
rb_create(uint32_t size)85 static ringbuf_handle_t rb_create(uint32_t size)
86 {
87     if (size < (BUFFER_MIN_SIZE << 2))
88     {
89         rt_kprintf("Invalid buffer size, Minimum = %d", (int32_t)(BUFFER_MIN_SIZE << 2));
90         return NULL;
91     }
92 
93     ringbuf_handle_t rb = NULL;
94     char *buf = NULL;
95 
96     do
97     {
98         bool _success =
99             (
100                 (rb                 = rt_malloc(sizeof(ringBuf)))   &&
101                 (buf                = rt_malloc(size))              &&
102                 (rb->semaphore_rb   = rt_sem_create("rb_sem", 0, RT_IPC_FLAG_PRIO))
103 
104             );
105 
106         if (!_success)
107         {
108             break;
109         }
110 
111         rb->is_give = 0;
112         rb->buf = buf;
113         rb->head = rb->tail = 0;
114         rb->size = size;
115         return rb;
116 
117     }
118     while (0);
119 
120     rb_destroy(rb);
121     return NULL;
122 }
123 
rb_get_count(ringbuf_handle_t rb)124 static uint32_t rb_get_count(ringbuf_handle_t rb)
125 {
126     uint32_t tail = rb->tail;
127 
128     if (rb->head >= tail)
129     {
130         return (rb->head - tail);
131     }
132 
133     return (rb->size - (tail - rb->head));
134 }
135 
rb_get_free(ringbuf_handle_t rb)136 static uint32_t rb_get_free(ringbuf_handle_t rb)
137 {
138     /** < Free a byte to judge the ringbuffer direction */
139     return (rb->size - rb_get_count(rb) - 1);
140 }
141 
rb_flush(ringbuf_handle_t rb)142 static rt_err_t rb_flush(ringbuf_handle_t rb)
143 {
144     rb->tail = rb->head = 0;
145     return RT_EOK;
146 }
147 
rb_read_byte(ringbuf_handle_t rb,uint8_t * outdata)148 static rt_err_t rb_read_byte(ringbuf_handle_t rb, uint8_t *outdata)
149 {
150     uint32_t tail = rb->tail;
151 
152     if (tail == rb->head)
153     {
154         return RT_ERROR;
155     }
156 
157     // Send a byte from the buffer
158     *outdata = rb->buf[tail];
159 
160     // Update tail position
161     tail++;
162 
163     if (tail == rb->size)
164     {
165         tail = 0;
166     }
167 
168     rb->tail = tail;
169     return RT_EOK;
170 }
171 
rb_write_byte(ringbuf_handle_t rb,const uint8_t indata)172 static rt_err_t rb_write_byte(ringbuf_handle_t rb, const uint8_t indata)
173 {
174     // Calculate next head
175     uint32_t next_head = rb->head + 1;
176 
177     if (next_head == rb->size)
178     {
179         next_head = 0;
180     }
181 
182     if (next_head == rb->tail)
183     {
184         return RT_ERROR;
185     }
186 
187     // Store data and advance head
188     rb->buf[rb->head] = indata;
189     rb->head = next_head;
190     return RT_EOK;
191 }
192 
rb_wait_semaphore(ringbuf_handle_t rb,rt_tick_t ticks_to_wait)193 static rt_err_t rb_wait_semaphore(ringbuf_handle_t rb, rt_tick_t ticks_to_wait)
194 {
195     rb->is_give = 0; /**< As long as it's written, it's allowed to give semaphore again */
196 
197     if (rt_sem_take(rb->semaphore_rb, ticks_to_wait) == RT_EOK)
198     {
199         return RT_EOK;
200     }
201 
202     return RT_ERROR;
203 }
204 
pwm_audio_wait_complete(rt_tick_t ticks_to_wait)205 rt_err_t pwm_audio_wait_complete(rt_tick_t ticks_to_wait)
206 {
207     pwm_audio_handle_t handle = g_pwm_audio_handle;
208 
209     if (rt_sem_take(handle->sem_complete, ticks_to_wait) == RT_EOK)
210     {
211         return RT_EOK;
212     }
213 
214     return RT_ERROR;
215 }
216 
pwm_audio_init(const pwm_audio_config_t * cfg)217 rt_err_t pwm_audio_init(const pwm_audio_config_t *cfg)
218 {
219     rt_err_t res = RT_EOK;
220 
221     pwm_audio_handle_t handle = NULL;
222 
223     int level = rt_hw_interrupt_disable();
224 
225     handle = rt_malloc(sizeof(pwm_audio_handle));
226     RT_ASSERT(handle != NULL);
227     memset(handle, 0, sizeof(pwm_audio_handle));
228 
229     handle->ringbuf = rb_create(cfg->ringbuf_len);
230     RT_ASSERT(handle->ringbuf != NULL);
231 
232     handle->sem_complete = rt_sem_create("pwm_cpl_sem", 0, RT_IPC_FLAG_PRIO);
233     RT_ASSERT(handle->sem_complete != NULL);
234 
235     handle->config = *cfg;
236     g_pwm_audio_handle = handle;
237 
238     handle->channel_mask = 0;
239 
240     if (handle->config.gpio_num_left >= 0)
241     {
242         handle->channel_mask |= CHANNEL_LEFT_MASK;
243     }
244 
245     if (handle->config.gpio_num_right >= 0)
246     {
247         handle->channel_mask |= CHANNEL_RIGHT_MASK;
248     }
249 
250     RT_ASSERT(0 != handle->channel_mask);
251 
252     //
253     handle->pwm_timer_cfg = g_timer6_cfg;
254     handle->pwm_timer_ctrl = &g_timer6_ctrl;
255 
256     R_GPT_Open(handle->pwm_timer_ctrl, &handle->pwm_timer_cfg);
257     R_GPT_Start(handle->pwm_timer_ctrl);
258     //
259 
260     /**< set a initial parameter */
261 //    res = pwm_audio_set_param(16000, 8, 2);
262 
263     handle->status = PWM_AUDIO_STATUS_IDLE;
264 
265     rt_hw_interrupt_enable(level);
266 
267     return res;
268 }
269 
pwm_audio_set_param(int rate,uint8_t bits,int ch)270 rt_err_t pwm_audio_set_param(int rate, uint8_t bits, int ch)
271 {
272     rt_err_t res = RT_EOK;
273 
274     RT_ASSERT(g_pwm_audio_handle->status != PWM_AUDIO_STATUS_BUSY);
275     RT_ASSERT(rate <= SAMPLE_RATE_MAX && rate >= SAMPLE_RATE_MIN);
276     RT_ASSERT(bits == 32 || bits == 16 || bits == 8);
277     RT_ASSERT(ch <= 2 && ch >= 1);
278 
279     pwm_audio_handle_t handle = g_pwm_audio_handle;
280 
281     handle->framerate = rate;
282     handle->bits_per_sample = bits;
283     handle->channel_set_num = ch;
284 
285     handle->gen_timer_cfg = g_timer2_cfg;
286     handle->gen_timer_ctrl = &g_timer2_ctrl;
287 
288     timer_cfg_t *config = NULL;
289     config = (struct st_timer_cfg *)&g_timer2_cfg;
290 
291     R_GPT_Open(handle->gen_timer_ctrl, &handle->gen_timer_cfg);
292     R_GPT_Start(handle->gen_timer_ctrl);
293 
294     return res;
295 }
296 
pwm_audio_set_volume(int8_t volume)297 rt_err_t pwm_audio_set_volume(int8_t volume)
298 {
299     if (volume < 0)
300     {
301         RT_ASSERT(-volume <= VOLUME_0DB);
302     }
303     else
304     {
305         RT_ASSERT(volume <= VOLUME_0DB);
306     }
307 
308     pwm_audio_handle_t handle = g_pwm_audio_handle;
309     handle->volume = volume + VOLUME_0DB;
310 
311     rt_kprintf("set volume to:%d\n", handle->volume);
312     return RT_EOK;
313 }
314 
pwm_audio_write(uint8_t * inbuf,size_t inbuf_len,size_t * bytes_written,rt_tick_t ticks_to_wait)315 rt_err_t pwm_audio_write(uint8_t *inbuf, size_t inbuf_len, size_t *bytes_written, rt_tick_t ticks_to_wait)
316 {
317     rt_err_t res = RT_EOK;
318     pwm_audio_handle_t handle = g_pwm_audio_handle;
319 
320     RT_ASSERT(inbuf != NULL && bytes_written != NULL && inbuf_len != 0);
321 
322     *bytes_written = 0;
323     ringbuf_handle_t rb = handle->ringbuf;
324     rt_tick_t start_ticks = rt_tick_get();
325 
326     while (inbuf_len)
327     {
328         if (RT_EOK == rb_wait_semaphore(rb, ticks_to_wait))
329         {
330             uint32_t free = rb_get_free(rb);
331             uint32_t bytes_can_write = inbuf_len;
332 
333             if (inbuf_len > free)
334             {
335                 bytes_can_write = free;
336             }
337 
338             bytes_can_write &= 0xfffffffc;  /**< Aligned data, bytes_can_write should be an integral multiple of 4 */
339 
340             if (0 == bytes_can_write)
341             {
342                 *bytes_written += inbuf_len;    /**< Discard the last misaligned bytes of data directly */
343                 return RT_EOK;
344             }
345 
346             /**< Get the difference between PWM resolution and audio samplewidth */
347             int8_t shift = handle->bits_per_sample - handle->config.duty_resolution;
348             uint32_t len = bytes_can_write;
349 
350             switch (handle->bits_per_sample)
351             {
352             case 8:
353             {
354                 if (shift < 0)
355                 {
356                     /**< When the PWM resolution is greater than 8 bits, the value needs to be expanded */
357                     uint16_t value;
358                     uint8_t temp;
359                     shift = -shift;
360                     len >>= 1;
361                     bytes_can_write >>= 1;
362 
363                     for (size_t i = 0; i < len; i++)
364                     {
365                         temp = (inbuf[i] * handle->volume / VOLUME_0DB) + 0x7f; /**< offset */
366                         value = temp << shift;
367                         rb_write_byte(rb, value);
368                         rb_write_byte(rb, value >> 8);
369                     }
370                 }
371                 else
372                 {
373                     uint8_t value;
374 
375                     for (size_t i = 0; i < len; i++)
376                     {
377                         value = (inbuf[i] * handle->volume / VOLUME_0DB) + 0x7f; /**< offset */
378                         rb_write_byte(rb, value);
379                     }
380                 }
381             }
382             break;
383 
384             case 16:
385             {
386                 len >>= 1;
387                 uint16_t *buf_16b = (uint16_t *)inbuf;
388                 static uint16_t value_16b;
389                 int16_t temp;
390 
391                 if (handle->config.duty_resolution > 8)
392                 {
393                     for (size_t i = 0; i < len; i++)
394                     {
395                         temp = buf_16b[i];
396                         temp = temp * handle->volume / VOLUME_0DB;
397                         value_16b = temp + 0x7fff; /**< offset */
398                         value_16b >>= shift;
399                         rb_write_byte(rb, value_16b);
400                         rb_write_byte(rb, value_16b >> 8);
401                     }
402                 }
403                 else
404                 {
405                     /**
406                      * When the PWM resolution is 8 bit, only one byte is transmitted
407                      */
408                     for (size_t i = 0; i < len; i++)
409                     {
410                         temp = buf_16b[i];
411                         temp = temp * handle->volume / VOLUME_0DB;
412                         value_16b = temp + 0x7fff; /**< offset */
413                         value_16b >>= shift;
414                         rb_write_byte(rb, value_16b);
415                     }
416                 }
417             }
418             break;
419 
420             case 32:
421             {
422                 len >>= 2;
423                 uint32_t *buf_32b = (uint32_t *)inbuf;
424                 uint32_t value;
425                 int32_t temp;
426 
427                 if (handle->config.duty_resolution > 8)
428                 {
429                     for (size_t i = 0; i < len; i++)
430                     {
431                         temp = buf_32b[i];
432                         temp = temp * handle->volume / VOLUME_0DB;
433                         value = temp + 0x7fffffff; /**< offset */
434                         value >>= shift;
435                         rb_write_byte(rb, value);
436                         rb_write_byte(rb, value >> 8);
437                     }
438                 }
439                 else
440                 {
441                     /**
442                      * When the PWM resolution is 8 bit, only one byte is transmitted
443                      */
444                     for (size_t i = 0; i < len; i++)
445                     {
446                         temp = buf_32b[i];
447                         temp = temp * handle->volume / VOLUME_0DB;
448                         value = temp + 0x7fffffff; /**< offset */
449                         value >>= shift;
450                         rb_write_byte(rb, value);
451                     }
452                 }
453             }
454             break;
455             default:
456                 break;
457             }
458 
459             inbuf += bytes_can_write;
460             inbuf_len -= bytes_can_write;
461             *bytes_written += bytes_can_write;
462         }
463         else
464         {
465             res = RT_ERROR;
466         }
467 
468         if ((rt_tick_get() - start_ticks) >= ticks_to_wait)
469         {
470             return res;
471         }
472     }
473 
474     return res;
475 }
476 
477 /*
478  * Note:
479  * In order to improve efficiency, register is operated directly
480  */
ledc_set_left_duty_fast(uint32_t duty_val)481 static inline void ledc_set_left_duty_fast(uint32_t duty_val)
482 {
483     pwm_audio_handle_t handle = g_pwm_audio_handle;
484 //    *g_ledc_left_duty_val = (duty_val) << 4; /* Discard decimal part */
485     R_GPT_DutyCycleSet(handle->pwm_timer_ctrl, duty_val, GPT_IO_PIN_GTIOCA);
486 }
487 
ledc_set_right_duty_fast(uint32_t duty_val)488 static inline void ledc_set_right_duty_fast(uint32_t duty_val)
489 {
490     pwm_audio_handle_t handle = g_pwm_audio_handle;
491 //    *g_ledc_right_duty_val = (duty_val) << 4; /* Discard decimal part */
492     R_GPT_DutyCycleSet(handle->pwm_timer_ctrl, duty_val, GPT_IO_PIN_GTIOCB);
493 }
494 
cb_timer2(timer_callback_args_t * p_args)495 void cb_timer2(timer_callback_args_t *p_args)
496 {
497     rt_interrupt_enter();
498 
499     pwm_audio_handle_t handle = g_pwm_audio_handle;
500 
501     if (handle == NULL)
502     {
503         rt_kprintf("pwm audio not initialized\n");
504         return;
505     }
506 
507     static uint8_t wave_h, wave_l;
508     static uint16_t value;
509     ringbuf_handle_t rb = handle->ringbuf;
510 
511     /**
512      * It is believed that the channel configured with GPIO needs to output sound
513     */
514     if (handle->channel_mask & CHANNEL_LEFT_MASK)
515     {
516         if (handle->config.duty_resolution > 8)
517         {
518             if (rb_get_count(rb) > 1)
519             {
520                 rb_read_byte(rb, &wave_l);
521                 rb_read_byte(rb, &wave_h);
522                 value = ((wave_h << 8) | wave_l);
523                 ledc_set_left_duty_fast(value);/**< set the PWM duty */
524             }
525         }
526         else
527         {
528             if (RT_EOK == rb_read_byte(rb, &wave_h))
529             {
530                 ledc_set_left_duty_fast(wave_h);/**< set the PWM duty */
531             }
532         }
533     }
534 
535     /**
536      * If two gpios are configured, but the audio data has only one channel, copy the data to the right channel
537      * Instead, the right channel data is discarded
538     */
539     if (handle->channel_mask & CHANNEL_RIGHT_MASK)
540     {
541         if (handle->channel_set_num == 1)
542         {
543             if (handle->config.duty_resolution > 8)
544             {
545                 ledc_set_right_duty_fast(value);/**< set the PWM duty */
546             }
547             else
548             {
549                 ledc_set_right_duty_fast(wave_h);/**< set the PWM duty */
550             }
551         }
552         else
553         {
554             if (handle->config.duty_resolution > 8)
555             {
556                 if (rb_get_count(rb) > 1)
557                 {
558                     rb_read_byte(rb, &wave_l);
559                     rb_read_byte(rb, &wave_h);
560                     value = ((wave_h << 8) | wave_l);
561                     ledc_set_right_duty_fast(value);/**< set the PWM duty */
562                 }
563             }
564             else
565             {
566                 if (RT_EOK == rb_read_byte(rb, &wave_h))
567                 {
568                     ledc_set_right_duty_fast(wave_h);/**< set the PWM duty */
569                 }
570             }
571         }
572     }
573     else
574     {
575         if (handle->channel_set_num == 2)
576         {
577             /**
578              * Discard the right channel data only if the right channel is configured but the audio data is stereo
579              * Read buffer but do nothing
580              */
581             if (handle->config.duty_resolution > 8)
582             {
583                 if (rb_get_count(rb) > 1)
584                 {
585                     rb_read_byte(rb, &wave_h);
586                     rb_read_byte(rb, &wave_h);
587                 }
588             }
589             else
590             {
591                 rb_read_byte(rb, &wave_h);
592             }
593 
594             rb_read_byte(rb, &wave_l);
595         }
596     }
597 
598     /**
599      * Send semaphore when buffer free is more than BUFFER_MIN_SIZE
600      */
601     if (0 == rb->is_give && rb_get_free(rb) > BUFFER_MIN_SIZE)
602     {
603         /**< The execution time of the following code is 2.71 microsecond */
604         rb->is_give = 1; /**< To prevent multiple give semaphores */
605 
606         int err = -RT_ERROR;
607 
608         rt_interrupt_enter();
609         err = rt_sem_release(rb->semaphore_rb);
610         rt_interrupt_leave();
611 
612         if (rb_get_count(rb) <= 1)
613         {
614             rt_interrupt_enter();
615             err = rt_sem_release(handle->sem_complete);
616             rt_interrupt_leave();
617         }
618         if (err != RT_ERROR)
619         {
620             rt_thread_yield();
621         }
622     }
623 
624     rt_interrupt_leave();
625 }
626 
pwm_audio_start(void)627 rt_err_t pwm_audio_start(void)
628 {
629     pwm_audio_handle_t handle = g_pwm_audio_handle;
630     RT_ASSERT(NULL != handle);
631     RT_ASSERT(handle->status == PWM_AUDIO_STATUS_IDLE);
632 
633     handle->status = PWM_AUDIO_STATUS_BUSY;
634 
635     /**< timer enable interrupt */
636     int level = rt_hw_interrupt_disable();
637     R_GPT_Start(handle->gen_timer_ctrl);
638     rt_hw_interrupt_enable(level);
639 
640     return RT_EOK;
641 }
642 
pwm_audio_stop(void)643 rt_err_t pwm_audio_stop(void)
644 {
645     pwm_audio_handle_t handle = g_pwm_audio_handle;
646 
647     /**< just disable timer ,keep pwm output to reduce switching nosie */
648     /**< timer disable interrupt */
649     int level = rt_hw_interrupt_disable();
650     R_GPT_Stop(handle->gen_timer_ctrl);
651     rt_hw_interrupt_enable(level);
652 
653     rb_flush(handle->ringbuf);  /**< flush ringbuf, avoid play noise */
654     handle->status = PWM_AUDIO_STATUS_IDLE;
655     return RT_EOK;
656 }
657 
pwm_audio_deinit(void)658 rt_err_t pwm_audio_deinit(void)
659 {
660     pwm_audio_handle_t handle = g_pwm_audio_handle;
661     RT_ASSERT(handle != NULL);
662 
663     handle->status = PWM_AUDIO_STATUS_UN_INIT;
664     R_GPT_Close(handle->pwm_timer_ctrl);
665     R_GPT_Close(handle->gen_timer_ctrl);
666     rt_sem_delete(handle->sem_complete);
667     rb_destroy(handle->ringbuf);
668     rt_free(handle);
669     return RT_EOK;
670 }
671