diff --git a/meson.build b/meson.build
index a2f7c013..876eca31 100644
--- a/meson.build
+++ b/meson.build
@@ -310,12 +310,14 @@ dm1801_def = def + mk22fn512_def + {'PLATFORM_DM1801': ''}
##
mod17_src = src + stm32f405_src + ['platform/targets/Module17/platform.c',
'platform/drivers/display/SH110x_Mod17.c',
+ 'platform/drivers/ADC/ADC1_Mod17.c',
'platform/drivers/keyboard/keyboard_Mod17.c',
'platform/drivers/NVM/nvmem_Mod17.c',
'platform/drivers/baseband/radio_Mod17.cpp',
'platform/drivers/audio/inputStream_Mod17.cpp',
'platform/drivers/audio/outputStream_Mod17.c',
- 'platform/drivers/audio/audio_Mod17.c']
+ 'platform/drivers/audio/audio_Mod17.c',
+ 'platform/drivers/baseband/MCP4551_Mod17.cpp']
mod17_inc = inc + stm32f405_inc + ['platform/targets/Module17']
mod17_def = def + stm32f405_def + {'PLATFORM_MOD17': ''}
diff --git a/openrtx/src/battery.c b/openrtx/src/battery.c
index f350c760..5105a88f 100644
--- a/openrtx/src/battery.c
+++ b/openrtx/src/battery.c
@@ -35,6 +35,9 @@ static const uint16_t bat_v_max = 0x0819; // 8.10V
#elif defined BAT_LIPO_3S
static const uint16_t bat_v_min = 0x0AD4; // 10.83V
static const uint16_t bat_v_max = 0x0C73; // 12.45V
+#elif defined BAT_MOD17
+static const uint16_t bat_v_min = 0x0600; // 6.00V
+static const uint16_t bat_v_max = 0x0DCD; // 13.8V
#elif defined BAT_NONE
static const uint16_t bat_v_min = 0;
static const uint16_t bat_v_max = 0;
diff --git a/platform/drivers/ADC/ADC1_Mod17.c b/platform/drivers/ADC/ADC1_Mod17.c
new file mode 100644
index 00000000..4e361972
--- /dev/null
+++ b/platform/drivers/ADC/ADC1_Mod17.c
@@ -0,0 +1,92 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Silvano Seva IU2KWO and Niccolò Izzo IU2KIN *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include
+#include "ADC1_Mod17.h"
+
+pthread_mutex_t adcMutex;
+
+void adc1_init()
+{
+ pthread_mutex_init(&adcMutex, NULL);
+
+ RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
+ __DSB();
+
+ /*
+ * Configure GPIOs to analog input mode:
+ */
+ gpio_setMode(AIN_VBAT, INPUT_ANALOG);
+
+ /*
+ * ADC clock is APB2 frequency divided by 8, giving 10.5MHz.
+ * We set the sample time of each channel to 84 ADC cycles and we have that
+ * a conversion takes 12 cycles: total conversion time is then of ~9us.
+ */
+ ADC->CCR |= ADC_CCR_ADCPRE;
+ ADC1->SMPR2 = ADC_SMPR2_SMP3_2;
+
+ /*
+ * Convert one channel, no overrun interrupt, 12-bit resolution,
+ * no analog watchdog, discontinuous mode, no end of conversion interrupts,
+ * turn on ADC.
+ */
+ ADC1->SQR1 = 0;
+ ADC1->CR2 = ADC_CR2_ADON;
+}
+
+void adc1_terminate()
+{
+ pthread_mutex_destroy(&adcMutex);
+
+ ADC1->CR2 &= ~ADC_CR2_ADON;
+ RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN;
+ __DSB();
+}
+
+uint16_t adc1_getRawSample(uint8_t ch)
+{
+ if(ch > 15) return 0;
+
+ pthread_mutex_lock(&adcMutex);
+
+ ADC1->SQR3 = ch;
+ ADC1->CR2 |= ADC_CR2_SWSTART;
+ while((ADC1->SR & ADC_SR_EOC) == 0) ;
+ uint16_t value = ADC1->DR;
+
+ pthread_mutex_unlock(&adcMutex);
+
+ return value;
+}
+
+uint16_t adc1_getMeasurement(uint8_t ch)
+{
+ /*
+ * To avoid using floats, we convert the raw ADC sample to mV using 16.16
+ * fixed point math. The equation for conversion is (sample * 3300)/4096 but,
+ * since converting the raw ADC sample to 16.16 notation requires a left
+ * shift by 16 and dividing by 4096 is equivalent to shifting right by 12,
+ * we just shift left by four and then multiply by 3300.
+ * With respect to using floats, maximum error is -1mV.
+ */
+ uint32_t sample = (adc1_getRawSample(ch) << 4) * 3300;
+ return ((uint16_t) (sample >> 16));
+}
diff --git a/platform/drivers/ADC/ADC1_Mod17.h b/platform/drivers/ADC/ADC1_Mod17.h
new file mode 100644
index 00000000..924497f5
--- /dev/null
+++ b/platform/drivers/ADC/ADC1_Mod17.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * Copyright (C) 2020 by Silvano Seva IU2KWO and Niccolò Izzo IU2KIN *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef ADC1_H
+#define ADC1_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Driver for ADC1, used on Module 17 to sample input voltage
+ *
+ * NOTE: values inside the enum are the channel numbers of STM32 ADC1 peripheral.
+ */
+
+enum adcCh
+{
+ ADC_VBAT_CH = 3,
+};
+
+/**
+ * Initialise ADC1.
+ */
+void adc1_init();
+
+/**
+ * Turn off ADC1.
+ */
+void adc1_terminate();
+
+/**
+ * Get current measurement of a given channel returning the raw ADC value.
+ *
+ * NOTE: the mapping provided in enum adcCh DOES NOT correspond to the physical
+ * ADC channel mapping!
+ *
+ * @param ch: channel number.
+ * @return current value of the specified channel, in ADC counts.
+ */
+uint16_t adc1_getRawSample(uint8_t ch);
+
+/**
+ * Get current measurement of a given channel.
+ *
+ * NOTE: the mapping provided in enum adcCh DOES NOT correspond to the physical
+ * ADC channel mapping!
+ *
+ * @param ch: channel number.
+ * @return current value of the specified channel in mV.
+ */
+uint16_t adc1_getMeasurement(uint8_t ch);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ADC1_H */
diff --git a/platform/drivers/baseband/MCP4551.h b/platform/drivers/baseband/MCP4551.h
new file mode 100644
index 00000000..22c22d05
--- /dev/null
+++ b/platform/drivers/baseband/MCP4551.h
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * Mathis Schmieder DB9MAT *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#ifndef MCP4551_H
+#define MCP4551_H
+
+#include
+#include
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Common WIPER values
+#define MCP4551_WIPER_MID 0x080
+#define MCP4551_WIPER_A 0x100
+#define MCP4551_WIPER_B 0x000
+
+// Command definitions (sent to WIPER register)
+#define MCP4551_CMD_WRITE 0x00
+#define MCP4551_CMD_INC 0x04
+#define MCP4551_CMD_DEC 0x08
+#define MCP4551_CMD_READ 0x0C
+
+/**
+ * Initialise I2C.
+ */
+void i2c_init();
+
+void mcp4551_init(uint8_t addr);
+void mcp4551_setWiper(uint8_t devAddr, uint16_t value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MCP4551_H */
\ No newline at end of file
diff --git a/platform/drivers/baseband/MCP4551_Mod17.cpp b/platform/drivers/baseband/MCP4551_Mod17.cpp
new file mode 100644
index 00000000..81287f1e
--- /dev/null
+++ b/platform/drivers/baseband/MCP4551_Mod17.cpp
@@ -0,0 +1,203 @@
+/***************************************************************************
+ * Copyright (C) 2021 by Federico Amedeo Izzo IU2NUO, *
+ * Niccolò Izzo IU2KIN *
+ * Frederik Saraci IU2NRO *
+ * Silvano Seva IU2KWO *
+ * Mathis Schmieder DB9MAT *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, see *
+ ***************************************************************************/
+
+#include
+#include
+#include
+#include "MCP4551.h"
+
+/*
+ * Implementation of MCP4551 I2C interface.
+ *
+ * Hardware I2C is not yet implemented. Bit-bang, baby!
+ */
+
+void _i2c_start();
+void _i2c_stop();
+void _i2c_write(uint8_t val);
+uint8_t _i2c_read(bool ack);
+
+void i2c_init()
+{
+ gpio_setMode(I2C_SDA, INPUT);
+ gpio_setMode(I2C_SCL, OUTPUT);
+ gpio_clearPin(I2C_SCL);
+}
+
+void mcp4551_init(uint8_t addr)
+{
+ mcp4551_setWiper(addr, MCP4551_WIPER_MID);
+}
+
+void mcp4551_setWiper(uint8_t devAddr, uint16_t value)
+{
+ _i2c_start();
+ _i2c_write(devAddr << 1);
+ uint8_t temp = ((value >> 8 & 0x01) | MCP4551_CMD_WRITE);
+ _i2c_write(temp);
+ temp = (value & 0xFF);
+ _i2c_write(temp);
+ _i2c_stop();
+}
+
+/*uint16_t i2c_readReg16(uint8_t devAddr, uint8_t reg)
+{
+ _i2c_start();
+ _i2c_write(devAddr << 1);
+ _i2c_write(reg);
+ _i2c_start();
+ _i2c_write(devAddr | 0x01);
+ uint8_t valHi = _i2c_read(true);
+ uint8_t valLo = _i2c_read(false);
+ _i2c_stop();
+
+ return (valHi << 8) | valLo;
+} */
+
+/*
+ * Software I2C routine
+ */
+
+void _i2c_start()
+{
+ gpio_setMode(I2C_SDA, OUTPUT);
+
+ /*
+ * Lines commented to keep SCL high when idle
+ *
+ gpio_clearPin(I2C_SCL);
+ delayUs(2);
+ */
+
+ gpio_setPin(I2C_SDA);
+ delayUs(5);
+
+ gpio_setPin(I2C_SCL);
+ delayUs(5);
+
+ gpio_clearPin(I2C_SDA);
+ delayUs(5);
+
+ gpio_clearPin(I2C_SCL);
+ delayUs(6);
+}
+
+void _i2c_stop()
+{
+ gpio_setMode(I2C_SDA, OUTPUT);
+
+ gpio_clearPin(I2C_SCL);
+ delayUs(5);
+
+ gpio_clearPin(I2C_SDA);
+ delayUs(5);
+
+ gpio_setPin(I2C_SCL);
+ delayUs(5);
+
+ gpio_setPin(I2C_SDA);
+ delayUs(5);
+
+ /*
+ * Lines commented to keep SCL high when idle
+ *
+ gpio_clearPin(I2C_SCL);
+ delayUs(5);
+ */
+}
+
+void _i2c_write(uint8_t val)
+{
+ gpio_setMode(I2C_SDA, OUTPUT);
+
+ for(uint8_t i = 0; i < 8; i++)
+ {
+ gpio_clearPin(I2C_SCL);
+ delayUs(1);
+
+ if(val & 0x80)
+ {
+ gpio_setPin(I2C_SDA);
+ }
+ else
+ {
+ gpio_clearPin(I2C_SDA);
+ }
+
+ val <<= 1;
+ delayUs(1);
+ gpio_setPin(I2C_SCL);
+ delayUs(5);
+ }
+
+ /* Ensure SCL is low before releasing SDA */
+ gpio_clearPin(I2C_SCL);
+
+ /* Clock cycle for slave ACK/NACK */
+ gpio_setMode(I2C_SDA, INPUT_PULL_UP);
+ delayUs(5);
+ gpio_setPin(I2C_SCL);
+ delayUs(5);
+ gpio_clearPin(I2C_SCL);
+ delayUs(1);
+
+ /* Asserting SDA pin allows to fastly bring the line to idle state */
+ gpio_setPin(I2C_SDA);
+ gpio_setMode(I2C_SDA, OUTPUT);
+ delayUs(6);
+}
+
+uint8_t _i2c_read(bool ack)
+{
+ gpio_setMode(I2C_SDA, INPUT_PULL_UP);
+ gpio_clearPin(I2C_SCL);
+
+ uint8_t value = 0;
+ for(uint8_t i = 0; i < 8; i++)
+ {
+ delayUs(5);
+ gpio_setPin(I2C_SCL);
+ delayUs(5);
+
+ value <<= 1;
+ value |= gpio_readPin(I2C_SDA);
+
+ gpio_clearPin(I2C_SCL);
+ }
+
+ /*
+ * Set ACK/NACK state BEFORE putting SDA gpio to output mode.
+ * This avoids spurious spikes which can be interpreted as NACKs
+ */
+ gpio_clearPin(I2C_SDA);
+ gpio_setMode(I2C_SDA, OUTPUT);
+ delayUs(5);
+ if(!ack) gpio_setPin(I2C_SDA);
+
+ /* Clock cycle for ACK/NACK */
+ delayUs(5);
+ gpio_setPin(I2C_SCL);
+ delayUs(5);
+ gpio_clearPin(I2C_SCL);
+ delayUs(5);
+
+ return value;
+}
\ No newline at end of file
diff --git a/platform/drivers/display/SSD1306_Mod17.c b/platform/drivers/display/SSD1306_Mod17.c
index 534599b7..bc8a176d 100644
--- a/platform/drivers/display/SSD1306_Mod17.c
+++ b/platform/drivers/display/SSD1306_Mod17.c
@@ -15,6 +15,16 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
+ * As a special exception, if other files instantiate templates or use *
+ * macros or inline functions from this file, or you compile this file *
+ * and link it with other works to produce a work based on this file, *
+ * this file does not by itself cause the resulting work to be covered *
+ * by the GNU General Public License. However the source code for this *
+ * file must still be made available in accordance with the GNU General *
+ * Public License. This exception does not invalidate any other reasons *
+ * why a work based on this file might be covered by the GNU General *
+ * Public License. *
+ * *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see *
***************************************************************************/
@@ -80,41 +90,36 @@ void display_init()
gpio_clearPin(LCD_RS);
gpio_clearPin(LCD_RST); /* Reset controller */
- delayMs(1);
+ delayMs(50);
gpio_setPin(LCD_RST);
- delayMs(5);
+ delayMs(50);
gpio_clearPin(LCD_CS);
gpio_clearPin(LCD_RS); /* RS low -> command mode */
- spi2_sendRecv(0xAE); /* Disable Display */
- spi2_sendRecv(0x20); /* Set Memory Addressing Mode to horizontal addressing Mode */
+ spi2_sendRecv(0xAE); // SH110X_DISPLAYOFF,
+ spi2_sendRecv(0xd5); // SH110X_SETDISPLAYCLOCKDIV, 0x51,
+ spi2_sendRecv(0x51);
+ //spi2_sendRecv(0x20); // SH110X_MEMORYMODE,
+ spi2_sendRecv(0x81); // SH110X_SETCONTRAST, 0x4F,
+ spi2_sendRecv(0x4F);
+ spi2_sendRecv(0xAD); // SH110X_DCDC, 0x8A,
+ spi2_sendRecv(0x8A);
+ spi2_sendRecv(0xA0); // SH110X_SEGREMAP,
+ spi2_sendRecv(0xC0); // SH110X_COMSCANINC,
+ spi2_sendRecv(0xDC); // SH110X_SETDISPSTARTLINE, 0x0,
spi2_sendRecv(0x00);
- spi2_sendRecv(0xB0); /* Set Page Start Address for Page Addressing Mode */
- spi2_sendRecv(0xC8); /* Set COM Output Scan Direction */
- spi2_sendRecv(0x00); /* Set low column address */
- spi2_sendRecv(0x10); /* Set high column address */
- spi2_sendRecv(0x40); /* Set start line address */
- spi2_sendRecv(0x81); /* Set contrast */
- spi2_sendRecv(0xCF);
- spi2_sendRecv(0xA1); /* Set segment re-map 0 to 127 */
- spi2_sendRecv(0xA6); /* Set normal color */
- spi2_sendRecv(0xA8); /* Set multiplex ratio (1 to 64) */
- spi2_sendRecv(0x3F);
- spi2_sendRecv(0xA4); /* Output follows RAM content */
- spi2_sendRecv(0xD3); /* Set display offset */
- spi2_sendRecv(0x00); /* Not offset */
- spi2_sendRecv(0xD5); /* Set display clock divide ratio/oscillator frequency */
- spi2_sendRecv(0xF0); /* Set divide ratio */
- spi2_sendRecv(0xD9); /* Set pre-charge period */
+ spi2_sendRecv(0xd3); // SH110X_SETDISPLAYOFFSET, 0x60,
+ spi2_sendRecv(0x60);
+ spi2_sendRecv(0xd9); // SH110X_SETPRECHARGE, 0x22,
spi2_sendRecv(0x22);
- spi2_sendRecv(0xDA); /* Set com pins hardware configuration */
- spi2_sendRecv(0x12);
- spi2_sendRecv(0xDB); /* Set vcomh */
- spi2_sendRecv(0x40);
- spi2_sendRecv(0x8D); /* Set DC-DC enable */
- spi2_sendRecv(0x14);
- spi2_sendRecv(0xAF); /* Enable Display */
+ spi2_sendRecv(0xdb); // SH110X_SETVCOMDETECT, 0x35,
+ spi2_sendRecv(0x35);
+ spi2_sendRecv(0xa8); // SH110X_SETMULTIPLEX, 0x3F,
+ spi2_sendRecv(0x3f);
+ spi2_sendRecv(0xa4); // SH110X_DISPLAYALLON_RESUME,
+ spi2_sendRecv(0xa6); // SH110X_NORMALDISPLAY,
+ spi2_sendRecv(0xAF); // SH110x_DISPLAYON
gpio_setPin(LCD_CS);
}
@@ -130,36 +135,26 @@ void display_terminate()
void display_renderRow(uint8_t row)
{
- /* magic stuff */
- uint8_t *buf = (frameBuffer + 128 * row);
- for (uint8_t i = 0; i<16; i++)
- {
- uint8_t tmp[8] = {0};
- for (uint8_t j = 0; j < 8; j++)
- {
- uint8_t tmp_buf = buf[j*16 + i];
- int count = __builtin_popcount(tmp_buf);
- while (count > 0)
- {
- int pos = __builtin_ctz(tmp_buf);
- tmp[pos] |= 1UL << j;
- tmp_buf &= ~(1 << pos);
- count--;
- }
- }
+ uint8_t *buf = (frameBuffer);
- for (uint8_t s = 0; s < 8; s++)
- {
- (void) spi2_sendRecv(tmp[s]);
- }
- }
+ for(uint16_t i=0; i<64; i++)
+ {
+ uint8_t out=0, tmp=buf[i*16 + 15-row];
+
+ for(uint8_t j=0; j<8; j++)
+ {
+ out|=((tmp>>(7-j))&1)< command mode */
(void) spi2_sendRecv(0xB0 | row); /* Set Y position */
@@ -168,13 +163,13 @@ void display_renderRows(uint8_t startRow, uint8_t endRow)
gpio_setPin(LCD_RS); /* RS high -> data mode */
display_renderRow(row);
}
-
+
gpio_setPin(LCD_CS);
}
void display_render()
{
- display_renderRows(0, SCREEN_HEIGHT / 8);
+ display_renderRows(0, SCREEN_WIDTH / 8 - 1);
}
bool display_renderingInProgress()
diff --git a/platform/targets/Module17/hwconfig.h b/platform/targets/Module17/hwconfig.h
index ec65f34a..e92102e3 100644
--- a/platform/targets/Module17/hwconfig.h
+++ b/platform/targets/Module17/hwconfig.h
@@ -39,7 +39,7 @@
#define PIX_FMT_BW
/* Device has no battery */
-#define BAT_NONE
+#define BAT_MOD17
/* Signalling LEDs */
#define PTT_LED GPIOC,8
@@ -75,4 +75,12 @@
#define MIC_MUTE GPIOC,4
#define MIC_GAIN GPIOC,5
+#define AIN_VBAT GPIOA,3
+
+/* I2C for MCP4551 */
+#define I2C_SDA GPIOB,7
+#define I2C_SCL GPIOB,6
+#define SOFTPOT_RX 0x2E
+#define SOFTPOT_TX 0x2F
+
#endif
diff --git a/platform/targets/Module17/platform.c b/platform/targets/Module17/platform.c
index a4c07f01..e088884c 100644
--- a/platform/targets/Module17/platform.c
+++ b/platform/targets/Module17/platform.c
@@ -27,6 +27,9 @@
#include
#include
#include
+#include
+#include
+#include
void platform_init()
{
@@ -39,6 +42,14 @@ void platform_init()
gpio_setMode(PTT_OUT, OUTPUT);
gpio_clearPin(PTT_OUT);
+ nvm_init();
+ adc1_init();
+ i2c_init();
+ mcp4551_init(SOFTPOT_RX);
+ mcp4551_init(SOFTPOT_TX);
+ //mcp4551_setWiper(SOFTPOT_RX, MCP4551_WIPER_A);
+ //mcp4551_setWiper(SOFTPOT_TX, MCP4551_WIPER_A);
+
audio_init();
}
@@ -48,11 +59,15 @@ void platform_terminate()
gpio_clearPin(PTT_LED);
gpio_clearPin(SYNC_LED);
gpio_clearPin(ERR_LED);
+
+ adc1_terminate();
+ nvm_terminate();
+ audio_terminate();
}
uint16_t platform_getVbat()
{
- return 0;
+ return adc1_getMeasurement(ADC_VBAT_CH)*5;
}
uint8_t platform_getMicLevel()