Skip to content

Commit c8087e0

Browse files
committed
pbio/drv/sound/sound_ev3: Implement beep-only driver
1 parent c5d323a commit c8087e0

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

lib/pbio/drv/sound/sound_ev3.c

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,119 @@
77

88
#include <stdint.h>
99

10-
void pbdrv_sound_stop() {
10+
#include <pbdrv/gpio.h>
11+
12+
#include <tiam1808/ehrpwm.h>
13+
#include <tiam1808/hw/soc_AM1808.h>
14+
#include <tiam1808/hw/hw_syscfg0_AM1808.h>
15+
#include <tiam1808/hw/hw_types.h>
16+
#include <tiam1808/psc.h>
17+
18+
#include "../drv/gpio/gpio_ev3.h"
1119

20+
// This module covers the frequency range from 64 Hz to 10 kHz.
21+
// It uses a maximum duty cycle of 1/16, and it controls volume
22+
// by shortening the duty cycle. The hardware has a resolution
23+
// of 16 bits for the period counter, and we want 8 bits for the volume,
24+
// so we use the following timebase division factors to make this work:
25+
//
26+
// 64 Hz - 900 Hz => /40
27+
// 900 Hz - 8 kHz => /4
28+
// 8 kHz - 10 kHz => /1
29+
30+
// Audio amplifier enable
31+
static const pbdrv_gpio_t pin_sound_en = PBDRV_GPIO_EV3_PIN(13, 3, 0, 6, 15);
32+
// Audio output pin
33+
#define SYSCFG_PINMUX3_PINMUX3_7_4_GPIO0_0 0
34+
static const pbdrv_gpio_t pin_audio = PBDRV_GPIO_EV3_PIN(3, 7, 4, 0, 0);
35+
36+
void pbdrv_sound_stop() {
37+
// Turn speaker amplifier off
38+
pbdrv_gpio_out_low(&pin_sound_en);
39+
// Clean up counter
40+
HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) |= EHRPWM_TBCTL_CTRMODE_STOPFREEZE;
41+
EHRPWMWriteTBCount(SOC_EHRPWM_0_REGS, 0);
1242
}
1343

1444
void pbdrv_beep_start(uint32_t frequency, uint16_t sample_attenuator) {
45+
// Clamp the frequency into the supported range
46+
if (frequency < 64) {
47+
frequency = 64;
48+
}
49+
if (frequency > 10000) {
50+
frequency = 10000;
51+
}
1552

53+
// Clamp the volume into the supported range
54+
if (sample_attenuator > INT16_MAX) {
55+
sample_attenuator = INT16_MAX;
56+
}
57+
// Extract bits[14:7] for our 8-bit volume resolution
58+
sample_attenuator >>= 7;
59+
60+
// Configure the timebase depending on which bucket the frequency is in.
61+
// Don't use EHRPWMTimebaseClkConfig because its calculation algorithm
62+
// isn't very good and is also tricky to fix.
63+
uint32_t timebase_div;
64+
if (frequency < 900) {
65+
timebase_div = 40;
66+
HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) = (HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) &
67+
~(EHRPWM_TBCTL_CLKDIV | EHRPWM_TBCTL_HSPCLKDIV)) |
68+
(EHRPWM_TBCTL_CLKDIV_DIVBY4 << EHRPWM_TBCTL_CLKDIV_SHIFT) |
69+
(EHRPWM_TBCTL_HSPCLKDIV_DIVBY10 << EHRPWM_TBCTL_HSPCLKDIV_SHIFT);
70+
} else if (frequency < 8000) {
71+
timebase_div = 4;
72+
HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) = (HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) &
73+
~(EHRPWM_TBCTL_CLKDIV | EHRPWM_TBCTL_HSPCLKDIV)) |
74+
(EHRPWM_TBCTL_CLKDIV_DIVBY4 << EHRPWM_TBCTL_CLKDIV_SHIFT) |
75+
(EHRPWM_TBCTL_HSPCLKDIV_DIVBY1 << EHRPWM_TBCTL_HSPCLKDIV_SHIFT);
76+
} else {
77+
timebase_div = 1;
78+
HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) = (HWREGH(SOC_EHRPWM_0_REGS + EHRPWM_TBCTL) &
79+
~(EHRPWM_TBCTL_CLKDIV | EHRPWM_TBCTL_HSPCLKDIV)) |
80+
(EHRPWM_TBCTL_CLKDIV_DIVBY1 << EHRPWM_TBCTL_CLKDIV_SHIFT) |
81+
(EHRPWM_TBCTL_HSPCLKDIV_DIVBY1 << EHRPWM_TBCTL_HSPCLKDIV_SHIFT);
82+
}
83+
84+
uint32_t pwm_period = (SOC_EHRPWM_0_MODULE_FREQ / timebase_div + frequency / 2) / frequency;
85+
uint32_t pwm_duty_cycle = (pwm_period * sample_attenuator / 256) / 16;
86+
87+
// Program PWM to generate a square wave of this frequency + duty cycle
88+
EHRPWMLoadCMPB(SOC_EHRPWM_0_REGS, pwm_duty_cycle, true, 0, true);
89+
EHRPWMPWMOpPeriodSet(SOC_EHRPWM_0_REGS, pwm_period, EHRPWM_COUNT_UP, true);
90+
91+
// Turn speaker amplifier on
92+
pbdrv_gpio_out_high(&pin_sound_en);
1693
}
1794

1895
void pbdrv_sound_init() {
96+
// Turn on EPWM
97+
PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_EHRPWM, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
98+
99+
// The stop function performs various initializations
100+
pbdrv_sound_stop();
101+
102+
// Program EPWM to generate the desired wave shape
103+
// Pulse goes high @ t=0
104+
// Pulse goes low @ t=CMPB
105+
EHRPWMConfigureAQActionOnB(
106+
SOC_EHRPWM_0_REGS,
107+
EHRPWM_AQCTLB_ZRO_EPWMXBHIGH,
108+
EHRPWM_AQCTLB_PRD_DONOTHING,
109+
EHRPWM_AQCTLB_CAU_DONOTHING,
110+
EHRPWM_AQCTLB_CAD_DONOTHING,
111+
EHRPWM_AQCTLB_CBU_EPWMXBLOW,
112+
EHRPWM_AQCTLB_CBD_DONOTHING,
113+
EHRPWM_AQSFRC_ACTSFB_DONOTHING
114+
);
115+
// Disable unused features
116+
EHRPWMDBOutput(SOC_EHRPWM_0_REGS, EHRPWM_DBCTL_OUT_MODE_BYPASS);
117+
EHRPWMChopperDisable(SOC_EHRPWM_0_REGS);
118+
EHRPWMTZTripEventDisable(SOC_EHRPWM_0_REGS, false);
119+
EHRPWMTZTripEventDisable(SOC_EHRPWM_0_REGS, true);
19120

121+
// Configure IO pin mode
122+
pbdrv_gpio_alt(&pin_audio, SYSCFG_PINMUX3_PINMUX3_7_4_EPWM0B);
20123
}
21124

22125
#endif // PBDRV_CONFIG_SOUND_EV3

0 commit comments

Comments
 (0)