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