aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob McWhirter <[email protected]>2021-06-10 15:33:43 -0400
committerBob McWhirter <[email protected]>2021-06-14 13:20:42 -0400
commitd58fb11b2e020a6a0b846e3437440ff688b2fe94 (patch)
tree13847832913a929eae437c8830c0268966f9ba6e
parent0dafd8f763a65558b88b2c7d55c933863c481d39 (diff)
ADCv3 and example.
-rw-r--r--embassy-stm32/src/adc/mod.rs125
-rw-r--r--embassy-stm32/src/adc/v3.rs317
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--examples/stm32l4/src/bin/adc.rs100
-rw-r--r--examples/stm32l4/src/bin/button.rs1
-rw-r--r--examples/stm32l4/src/bin/button_exti.rs1
-rw-r--r--examples/stm32l4/src/bin/dac.rs20
m---------stm32-data0
8 files changed, 554 insertions, 12 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
new file mode 100644
index 000000000..8cae5f1de
--- /dev/null
+++ b/embassy-stm32/src/adc/mod.rs
@@ -0,0 +1,125 @@
1#![macro_use]
2
3#[cfg_attr(adc_v3, path = "v3.rs")]
4mod _version;
5
6#[allow(unused)]
7pub use _version::*;
8
9use crate::gpio::NoPin;
10use crate::peripherals;
11
12pub(crate) mod sealed {
13 use crate::gpio::Pin;
14
15 pub trait Instance {
16 fn regs() -> &'static crate::pac::adc::Adc;
17 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon;
18 }
19
20 pub trait Common {
21 fn regs() -> &'static crate::pac::adccommon::AdcCommon;
22 }
23
24 pub trait AdcPin<T: Instance> {
25 fn channel(&self) -> u8;
26 }
27}
28
29pub trait Instance: sealed::Instance + 'static {}
30pub trait Common: sealed::Common + 'static {}
31pub trait AdcPin<T: Instance>: sealed::AdcPin<T> {}
32
33crate::pac::peripherals!(
34 (adc, $inst:ident) => {
35 impl crate::adc::sealed::Instance for peripherals::$inst {
36 fn regs() -> &'static crate::pac::adc::Adc {
37 &crate::pac::$inst
38 }
39 fn common_regs() -> &'static crate::pac::adccommon::AdcCommon {
40 crate::pac::peripherals!{
41 (adccommon, $common_inst:ident) => {
42 return &crate::pac::$common_inst
43 };
44 }
45 }
46 }
47
48 impl crate::adc::Instance for peripherals::$inst {}
49 };
50);
51
52crate::pac::peripherals!(
53 (adccommon, $inst:ident) => {
54 impl sealed::Common for peripherals::$inst {
55 fn regs() -> &'static crate::pac::adccommon::AdcCommon {
56 &crate::pac::$inst
57 }
58 }
59
60 impl crate::adc::Common for peripherals::$inst {}
61 };
62);
63
64macro_rules! impl_pin {
65 ($inst:ident, $pin:ident, $ch:expr) => {
66 impl AdcPin<peripherals::$inst> for peripherals::$pin {}
67
68 impl sealed::AdcPin<peripherals::$inst> for peripherals::$pin {
69 fn channel(&self) -> u8 {
70 $ch
71 }
72 }
73 };
74}
75
76crate::pac::peripheral_pins!(
77 ($inst:ident, adc, ADC, $pin:ident, IN1) => {
78 impl_pin!($inst, $pin, 1);
79 };
80 ($inst:ident, adc, ADC, $pin:ident, IN2) => {
81 impl_pin!($inst, $pin, 2);
82 };
83 ($inst:ident, adc, ADC, $pin:ident, IN3) => {
84 impl_pin!($inst, $pin, 3);
85 };
86 ($inst:ident, adc, ADC, $pin:ident, IN4) => {
87 impl_pin!($inst, $pin, 4);
88 };
89 ($inst:ident, adc, ADC, $pin:ident, IN5) => {
90 impl_pin!($inst, $pin, 5);
91 };
92 ($inst:ident, adc, ADC, $pin:ident, IN6) => {
93 impl_pin!($inst, $pin, 6);
94 };
95 ($inst:ident, adc, ADC, $pin:ident, IN7) => {
96 impl_pin!($inst, $pin, 7);
97 };
98 ($inst:ident, adc, ADC, $pin:ident, IN8) => {
99 impl_pin!($inst, $pin, 8);
100 };
101 ($inst:ident, adc, ADC, $pin:ident, IN9) => {
102 impl_pin!($inst, $pin, 9);
103 };
104 ($inst:ident, adc, ADC, $pin:ident, IN10) => {
105 impl_pin!($inst, $pin, 10);
106 };
107 ($inst:ident, adc, ADC, $pin:ident, IN11) => {
108 impl_pin!($inst, $pin, 11);
109 };
110 ($inst:ident, adc, ADC, $pin:ident, IN12) => {
111 impl_pin!($inst, $pin, 12);
112 };
113 ($inst:ident, adc, ADC, $pin:ident, IN13) => {
114 impl_pin!($inst, $pin, 13);
115 };
116 ($inst:ident, adc, ADC, $pin:ident, IN14) => {
117 impl_pin!($inst, $pin, 14);
118 };
119 ($inst:ident, adc, ADC, $pin:ident, IN15) => {
120 impl_pin!($inst, $pin, 15);
121 };
122 ($inst:ident, adc, ADC, $pin:ident, IN16) => {
123 impl_pin!($inst, $pin, 16);
124 };
125);
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
new file mode 100644
index 000000000..14c705b86
--- /dev/null
+++ b/embassy-stm32/src/adc/v3.rs
@@ -0,0 +1,317 @@
1use crate::adc::{AdcPin, Instance};
2use core::convert::Infallible;
3use core::marker::PhantomData;
4use cortex_m::delay::Delay;
5use embassy::util::Unborrow;
6use embassy_extras::unborrow;
7use embedded_hal::blocking::delay::{DelayMs, DelayUs};
8
9pub const VDDA_CALIB_MV: u32 = 3000;
10
11pub enum Resolution {
12 TwelveBit,
13 TenBit,
14 EightBit,
15 SixBit,
16}
17
18impl Default for Resolution {
19 fn default() -> Self {
20 Self::TwelveBit
21 }
22}
23
24impl Resolution {
25 fn res(&self) -> crate::pac::adc::vals::Res {
26 match self {
27 Resolution::TwelveBit => crate::pac::adc::vals::Res::TWELVEBIT,
28 Resolution::TenBit => crate::pac::adc::vals::Res::TENBIT,
29 Resolution::EightBit => crate::pac::adc::vals::Res::EIGHTBIT,
30 Resolution::SixBit => crate::pac::adc::vals::Res::SIXBIT,
31 }
32 }
33
34 fn to_max_count(&self) -> u32 {
35 match self {
36 Resolution::TwelveBit => (1 << 12) - 1,
37 Resolution::TenBit => (1 << 10) - 1,
38 Resolution::EightBit => (1 << 8) - 1,
39 Resolution::SixBit => (1 << 6) - 1,
40 }
41 }
42}
43
44pub struct Vref;
45impl<T: Instance> AdcPin<T> for Vref {}
46impl<T: Instance> super::sealed::AdcPin<T> for Vref {
47 fn channel(&self) -> u8 {
48 0
49 }
50}
51
52pub struct Temperature;
53impl<T: Instance> AdcPin<T> for Temperature {}
54impl<T: Instance> super::sealed::AdcPin<T> for Temperature {
55 fn channel(&self) -> u8 {
56 17
57 }
58}
59
60pub struct Vbat;
61impl<T: Instance> AdcPin<T> for Vbat {}
62impl<T: Instance> super::sealed::AdcPin<T> for Vbat {
63 fn channel(&self) -> u8 {
64 18
65 }
66}
67
68/// ADC sample time
69///
70/// The default setting is 2.5 ADC clock cycles.
71#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
72pub enum SampleTime {
73 /// 2.5 ADC clock cycles
74 Cycles2_5 = 0b000,
75
76 /// 6.5 ADC clock cycles
77 Cycles6_5 = 0b001,
78
79 /// 12.5 ADC clock cycles
80 Cycles12_5 = 0b010,
81
82 /// 24.5 ADC clock cycles
83 Cycles24_5 = 0b011,
84
85 /// 47.5 ADC clock cycles
86 Cycles47_5 = 0b100,
87
88 /// 92.5 ADC clock cycles
89 Cycles92_5 = 0b101,
90
91 /// 247.5 ADC clock cycles
92 Cycles247_5 = 0b110,
93
94 /// 640.5 ADC clock cycles
95 Cycles640_5 = 0b111,
96}
97
98impl SampleTime {
99 fn sample_time(&self) -> crate::pac::adc::vals::SampleTime {
100 match self {
101 SampleTime::Cycles2_5 => crate::pac::adc::vals::SampleTime::CYCLES2_5,
102 SampleTime::Cycles6_5 => crate::pac::adc::vals::SampleTime::CYCLES6_5,
103 SampleTime::Cycles12_5 => crate::pac::adc::vals::SampleTime::CYCLES12_5,
104 SampleTime::Cycles24_5 => crate::pac::adc::vals::SampleTime::CYCLES24_5,
105 SampleTime::Cycles47_5 => crate::pac::adc::vals::SampleTime::CYCLES47_5,
106 SampleTime::Cycles92_5 => crate::pac::adc::vals::SampleTime::CYCLES92_5,
107 SampleTime::Cycles247_5 => crate::pac::adc::vals::SampleTime::CYCLES247_5,
108 SampleTime::Cycles640_5 => crate::pac::adc::vals::SampleTime::CYCLES640_5,
109 }
110 }
111}
112
113impl Default for SampleTime {
114 fn default() -> Self {
115 Self::Cycles2_5
116 }
117}
118
119pub struct Adc<'d, T: Instance> {
120 sample_time: SampleTime,
121 calibrated_vdda: u32,
122 resolution: Resolution,
123 phantom: PhantomData<&'d mut T>,
124}
125
126impl<'d, T: Instance> Adc<'d, T> {
127 pub fn new(_peri: impl Unborrow<Target = T> + 'd, mut delay: Delay) -> (Self, Delay) {
128 unborrow!(_peri);
129 unsafe {
130 T::regs().cr().modify(|reg| {
131 reg.set_deeppwd(false);
132 reg.set_advregen(true);
133 });
134 }
135
136 delay.delay_us(20);
137
138 unsafe {
139 while T::regs().cr().read().adcal() {
140 // spin
141 }
142 }
143
144 delay.delay_us(1);
145
146 (
147 Self {
148 sample_time: Default::default(),
149 resolution: Resolution::default(),
150 calibrated_vdda: VDDA_CALIB_MV,
151 phantom: PhantomData,
152 },
153 delay,
154 )
155 }
156
157 pub fn enable_vref(&self, mut delay: Delay) -> (Vref, Delay) {
158 unsafe {
159 T::common_regs().ccr().modify(|reg| {
160 reg.set_vrefen(true);
161 });
162 }
163
164 // "Table 24. Embedded internal voltage reference" states that it takes a maximum of 12 us
165 // to stabilize the internal voltage reference, we wait a little more.
166 // TODO: delay 15us
167 //cortex_m::asm::delay(20_000_000);
168 delay.delay_us(15);
169
170 (Vref {}, delay)
171 }
172
173 pub fn enable_temperature(&self) -> Temperature {
174 unsafe {
175 T::common_regs().ccr().modify(|reg| {
176 reg.set_ch17sel(true);
177 });
178 }
179
180 Temperature {}
181 }
182
183 pub fn enable_vbat(&self) -> Vbat {
184 unsafe {
185 T::common_regs().ccr().modify(|reg| {
186 reg.set_ch18sel(true);
187 });
188 }
189
190 Vbat {}
191 }
192
193 /// Calculates the system VDDA by sampling the internal VREF channel and comparing
194 /// the result with the value stored at the factory. If the chip's VDDA is not stable, run
195 /// this before each ADC conversion.
196 fn calibrate(&mut self, vref: &mut Vref) {
197 let vref_cal = unsafe { crate::pac::VREFINTCAL.data().read().value() };
198 let old_sample_time = self.sample_time;
199
200 // "Table 24. Embedded internal voltage reference" states that the sample time needs to be
201 // at a minimum 4 us. With 640.5 ADC cycles we have a minimum of 8 us at 80 MHz, leaving
202 // some headroom.
203 self.sample_time = SampleTime::Cycles640_5;
204
205 // This can't actually fail, it's just in a result to satisfy hal trait
206 let vref_samp = self.read(vref);
207
208 self.sample_time = old_sample_time;
209
210 self.calibrated_vdda = (VDDA_CALIB_MV * u32::from(vref_cal)) / u32::from(vref_samp);
211 }
212
213 pub fn set_sample_time(&mut self, sample_time: SampleTime) {
214 self.sample_time = sample_time;
215 }
216
217 pub fn set_resolution(&mut self, resolution: Resolution) {
218 self.resolution = resolution;
219 }
220
221 /// Convert a measurement to millivolts
222 pub fn to_millivolts(&self, sample: u16) -> u16 {
223 ((u32::from(sample) * self.calibrated_vdda) / self.resolution.to_max_count()) as u16
224 }
225
226 /*
227 /// Convert a raw sample from the `Temperature` to deg C
228 pub fn to_degrees_centigrade(sample: u16) -> f32 {
229 (130.0 - 30.0) / (VtempCal130::get().read() as f32 - VtempCal30::get().read() as f32)
230 * (sample as f32 - VtempCal30::get().read() as f32)
231 + 30.0
232 }
233 */
234
235 pub fn read(&mut self, pin: &mut impl AdcPin<T>) -> u16 {
236 let v = pin.channel();
237
238 unsafe {
239 // Make sure bits are off
240 while T::regs().cr().read().addis() {
241 // spin
242 }
243
244 // Enable ADC
245 T::regs().isr().modify(|reg| {
246 reg.set_adrdy(true);
247 });
248 T::regs().cr().modify(|reg| {
249 reg.set_aden(true);
250 });
251
252 while !T::regs().isr().read().adrdy() {
253 // spin
254 }
255
256 // Configure ADC
257 T::regs()
258 .cfgr()
259 .modify(|reg| reg.set_res(self.resolution.res()));
260
261 // Configure channel
262 Self::set_channel_sample_time(pin.channel(), self.sample_time);
263
264 // Select channel
265 T::regs().sqr1().write(|reg| reg.set_sq(0, pin.channel()));
266
267 // Start conversion
268 T::regs().isr().modify(|reg| {
269 reg.set_eos(true);
270 reg.set_eoc(true);
271 });
272 T::regs().cr().modify(|reg| {
273 reg.set_adstart(true);
274 });
275
276 while !T::regs().isr().read().eos() {
277 // spin
278 }
279
280 // Read ADC value first time and discard it, as per errata sheet.
281 // The errata states that if we do conversions slower than 1 kHz, the
282 // first read ADC value can be corrupted, so we discard it and measure again.
283
284 let _ = T::regs().dr().read();
285
286 T::regs().isr().modify(|reg| {
287 reg.set_eos(true);
288 reg.set_eoc(true);
289 });
290 T::regs().cr().modify(|reg| {
291 reg.set_adstart(true);
292 });
293
294 while !T::regs().isr().read().eos() {
295 // spin
296 }
297
298 let val = T::regs().dr().read().0 as u16;
299
300 T::regs().cr().modify(|reg| reg.set_addis(true));
301
302 val
303 }
304 }
305
306 unsafe fn set_channel_sample_time(ch: u8, sample_time: SampleTime) {
307 if ch >= 0 && ch <= 9 {
308 T::regs()
309 .smpr1()
310 .modify(|reg| reg.set_smp(ch as _, sample_time.sample_time()));
311 } else {
312 T::regs()
313 .smpr2()
314 .modify(|reg| reg.set_smp((ch - 10) as _, sample_time.sample_time()));
315 }
316 }
317}
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index c205bc49d..6a08fc580 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -21,6 +21,8 @@ pub mod gpio;
21pub mod rcc; 21pub mod rcc;
22 22
23// Sometimes-present hardware 23// Sometimes-present hardware
24#[cfg(adc)]
25pub mod adc;
24#[cfg(timer)] 26#[cfg(timer)]
25pub mod clock; 27pub mod clock;
26#[cfg(dac)] 28#[cfg(dac)]
diff --git a/examples/stm32l4/src/bin/adc.rs b/examples/stm32l4/src/bin/adc.rs
new file mode 100644
index 000000000..fe97fb0b1
--- /dev/null
+++ b/examples/stm32l4/src/bin/adc.rs
@@ -0,0 +1,100 @@
1#![no_std]
2#![no_main]
3#![feature(trait_alias)]
4#![feature(min_type_alias_impl_trait)]
5#![feature(impl_trait_in_bindings)]
6#![feature(type_alias_impl_trait)]
7
8#[path = "../example_common.rs"]
9mod example_common;
10
11use embassy_stm32::gpio::{Input, Level, NoPin, Output, Pull};
12use embedded_hal::digital::v2::{InputPin, OutputPin};
13use example_common::*;
14
15use cortex_m_rt::entry;
16//use stm32f4::stm32f429 as pac;
17use cortex_m::delay::Delay;
18use embassy_stm32::adc::{Adc, Resolution};
19use embassy_stm32::dac::{Channel, Dac, Value};
20use embassy_stm32::spi::{ByteOrder, Config, Spi, MODE_0};
21use embassy_stm32::time::Hertz;
22use embedded_hal::blocking::spi::Transfer;
23use micromath::F32Ext;
24use stm32l4::stm32l4x5 as pac;
25use stm32l4xx_hal::gpio::PA4;
26use stm32l4xx_hal::rcc::PllSource;
27use stm32l4xx_hal::{prelude::*, rcc};
28
29#[entry]
30fn main() -> ! {
31 info!("Hello World, dude!");
32 //let pp = pac::Peripherals::take().unwrap();
33 let cp = cortex_m::Peripherals::take().unwrap();
34 let pp = stm32l4xx_hal::stm32::Peripherals::take().unwrap();
35 let mut flash = pp.FLASH.constrain();
36 let mut rcc = pp.RCC.constrain();
37 let mut pwr = pp.PWR.constrain(&mut rcc.apb1r1);
38
39 let mut delay = Delay::new(cp.SYST, 80_000_000);
40
41 // TRY the other clock configuration
42 // let clocks = rcc.cfgr.freeze(&mut flash.acr);
43 let clocks = rcc
44 .cfgr
45 .sysclk(80.mhz())
46 .pclk1(80.mhz())
47 .pclk2(80.mhz())
48 .pll_source(PllSource::HSI16)
49 .freeze(&mut flash.acr, &mut pwr);
50
51 let pp = unsafe { pac::Peripherals::steal() };
52
53 pp.RCC.ccipr.modify(|_, w| {
54 unsafe {
55 w.adcsel().bits(0b11);
56 }
57 w
58 });
59
60 pp.DBGMCU.cr.modify(|_, w| {
61 w.dbg_sleep().set_bit();
62 w.dbg_standby().set_bit();
63 w.dbg_stop().set_bit()
64 });
65
66 pp.RCC.ahb2enr.modify(|_, w| {
67 w.adcen().set_bit();
68 w.gpioaen().set_bit();
69 w.gpioben().set_bit();
70 w.gpiocen().set_bit();
71 w.gpioden().set_bit();
72 w.gpioeen().set_bit();
73 w.gpiofen().set_bit();
74 w
75 });
76
77 let p = embassy_stm32::init(Default::default());
78
79 let (mut adc, mut delay) = Adc::new(p.ADC1, delay);
80 //adc.enable_vref();
81 adc.set_resolution(Resolution::EightBit);
82 let mut channel = p.PC0;
83
84 loop {
85 let v = adc.read(&mut channel);
86 info!("--> {}", v);
87 }
88}
89
90fn to_sine_wave(v: u8) -> u8 {
91 if v >= 128 {
92 // top half
93 let r = 3.14 * ((v - 128) as f32 / 128.0);
94 (r.sin() * 128.0 + 127.0) as u8
95 } else {
96 // bottom half
97 let r = 3.14 + 3.14 * (v as f32 / 128.0);
98 (r.sin() * 128.0 + 127.0) as u8
99 }
100}
diff --git a/examples/stm32l4/src/bin/button.rs b/examples/stm32l4/src/bin/button.rs
index 43d81715a..962d5aa75 100644
--- a/examples/stm32l4/src/bin/button.rs
+++ b/examples/stm32l4/src/bin/button.rs
@@ -15,7 +15,6 @@ use example_common::*;
15use cortex_m_rt::entry; 15use cortex_m_rt::entry;
16use stm32l4::stm32l4x5 as pac; 16use stm32l4::stm32l4x5 as pac;
17 17
18
19#[entry] 18#[entry]
20fn main() -> ! { 19fn main() -> ! {
21 info!("Hello World!"); 20 info!("Hello World!");
diff --git a/examples/stm32l4/src/bin/button_exti.rs b/examples/stm32l4/src/bin/button_exti.rs
index caace8359..c6b7c83ec 100644
--- a/examples/stm32l4/src/bin/button_exti.rs
+++ b/examples/stm32l4/src/bin/button_exti.rs
@@ -80,5 +80,4 @@ fn main() -> ! {
80 executor.run(|spawner| { 80 executor.run(|spawner| {
81 unwrap!(spawner.spawn(main_task())); 81 unwrap!(spawner.spawn(main_task()));
82 }) 82 })
83
84} 83}
diff --git a/examples/stm32l4/src/bin/dac.rs b/examples/stm32l4/src/bin/dac.rs
index 5bd5dafbc..0ca40fbdb 100644
--- a/examples/stm32l4/src/bin/dac.rs
+++ b/examples/stm32l4/src/bin/dac.rs
@@ -8,20 +8,20 @@
8#[path = "../example_common.rs"] 8#[path = "../example_common.rs"]
9mod example_common; 9mod example_common;
10 10
11use embassy_stm32::gpio::{Level, Output, Input, Pull, NoPin}; 11use embassy_stm32::gpio::{Input, Level, NoPin, Output, Pull};
12use embedded_hal::digital::v2::{OutputPin, InputPin}; 12use embedded_hal::digital::v2::{InputPin, OutputPin};
13use example_common::*; 13use example_common::*;
14 14
15use cortex_m_rt::entry; 15use cortex_m_rt::entry;
16//use stm32f4::stm32f429 as pac; 16//use stm32f4::stm32f429 as pac;
17use stm32l4::stm32l4x5 as pac; 17use embassy_stm32::dac::{Channel, Dac, Value};
18use embassy_stm32::spi::{Spi, MODE_0, ByteOrder, Config}; 18use embassy_stm32::spi::{ByteOrder, Config, Spi, MODE_0};
19use embassy_stm32::time::Hertz; 19use embassy_stm32::time::Hertz;
20use embedded_hal::blocking::spi::Transfer; 20use embedded_hal::blocking::spi::Transfer;
21use stm32l4xx_hal::{rcc, prelude::*}; 21use stm32l4::stm32l4x5 as pac;
22use stm32l4xx_hal::rcc::PllSource;
23use embassy_stm32::dac::{Dac, Value, Channel};
24use stm32l4xx_hal::gpio::PA4; 22use stm32l4xx_hal::gpio::PA4;
23use stm32l4xx_hal::rcc::PllSource;
24use stm32l4xx_hal::{prelude::*, rcc};
25 25
26#[entry] 26#[entry]
27fn main() -> ! { 27fn main() -> ! {
@@ -72,7 +72,7 @@ fn main() -> ! {
72 loop { 72 loop {
73 for v in 0..=255 { 73 for v in 0..=255 {
74 dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v))); 74 dac.set(Channel::Ch1, Value::Bit8(to_sine_wave(v)));
75 dac.trigger( Channel::Ch1 ); 75 dac.trigger(Channel::Ch1);
76 } 76 }
77 } 77 }
78} 78}
@@ -82,11 +82,11 @@ use micromath::F32Ext;
82fn to_sine_wave(v: u8) -> u8 { 82fn to_sine_wave(v: u8) -> u8 {
83 if v >= 128 { 83 if v >= 128 {
84 // top half 84 // top half
85 let r = 3.14 * ( (v-128) as f32/ 128.0) ; 85 let r = 3.14 * ((v - 128) as f32 / 128.0);
86 (r.sin() * 128.0 + 127.0) as u8 86 (r.sin() * 128.0 + 127.0) as u8
87 } else { 87 } else {
88 // bottom half 88 // bottom half
89 let r = 3.14 + 3.14 * (v as f32/ 128.0); 89 let r = 3.14 + 3.14 * (v as f32 / 128.0);
90 (r.sin() * 128.0 + 127.0) as u8 90 (r.sin() * 128.0 + 127.0) as u8
91 } 91 }
92} 92}
diff --git a/stm32-data b/stm32-data
Subproject 8f32d8e4f25276f6f2155e8dd5bbed1acefd657 Subproject 67b2029a7f203e52f6e1f68c71c7d0aacfef579