summaryrefslogtreecommitdiffstats
path: root/watch-library/hardware
diff options
context:
space:
mode:
Diffstat (limited to 'watch-library/hardware')
-rwxr-xr-xwatch-library/hardware/linker/saml22j18.ld13
-rw-r--r--watch-library/hardware/watch/watch.c4
-rw-r--r--watch-library/hardware/watch/watch_private.c20
-rw-r--r--watch-library/hardware/watch/watch_storage.c94
4 files changed, 126 insertions, 5 deletions
diff --git a/watch-library/hardware/linker/saml22j18.ld b/watch-library/hardware/linker/saml22j18.ld
index a9801509..211e5346 100755
--- a/watch-library/hardware/linker/saml22j18.ld
+++ b/watch-library/hardware/linker/saml22j18.ld
@@ -32,11 +32,18 @@ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
SEARCH_DIR(.)
-/* Memory Spaces Definitions */
+/* Memory Space Definitions:
+ * 0x00000000-0x00002000: Bootloader (length 0x2000 or 8192 bytes)
+ * 0x00002000-0x0003C000: Firmware (length 0x3A000 or 237568 bytes)
+ * 0x0003C000-0x00040000: EEPROM Emulation (length 0x2000 or 8192 bytes)
+ * 0x20000000-0x20008000: RAM (length 0x8000 or 32768 bytes)
+ */
MEMORY
{
- rom (rx) : ORIGIN = 0x2000, LENGTH = 0x00040000-0x2000
- ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
+ bootloader (rx) : ORIGIN = 0x0, LENGTH = 0x2000
+ rom (rx) : ORIGIN = 0x2000, LENGTH = 0x00040000-0x2000-0x2000
+ eeprom (r) : ORIGIN = 0x00040000-0x2000, LENGTH = 0x2000
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
diff --git a/watch-library/hardware/watch/watch.c b/watch-library/hardware/watch/watch.c
index 32bbccbb..b3dc4e8d 100644
--- a/watch-library/hardware/watch/watch.c
+++ b/watch-library/hardware/watch/watch.c
@@ -41,3 +41,7 @@ void SYSTEM_Handler(void) {
bool watch_is_buzzer_or_led_enabled(void){
return hri_mclk_get_APBCMASK_TCC0_bit(MCLK);
}
+
+bool watch_is_usb_enabled(void) {
+ return USB->DEVICE.CTRLA.bit.ENABLE;
+}
diff --git a/watch-library/hardware/watch/watch_private.c b/watch-library/hardware/watch/watch_private.c
index 4b010d4a..cd607b8e 100644
--- a/watch-library/hardware/watch/watch_private.c
+++ b/watch-library/hardware/watch/watch_private.c
@@ -255,8 +255,15 @@ int _write(int file, char *ptr, int len) {
return 0;
}
-// this method could be overridden to read stuff from the USB console? but no need rn.
-int _read(void) {
+static char buf[256] = {0};
+
+int _read(int file, char *ptr, int len) {
+ (void)file;
+ int actual_length = strlen(buf);
+ if (actual_length) {
+ memcpy(ptr, buf, min(len, actual_length));
+ return actual_length;
+ }
return 0;
}
@@ -264,8 +271,17 @@ void USB_Handler(void) {
tud_int_handler(0);
}
+static void cdc_task(void) {
+ if (tud_cdc_n_available(0)) {
+ tud_cdc_n_read(0, buf, sizeof(buf));
+ } else {
+ memset(buf, 0, 256);
+ }
+}
+
void TC0_Handler(void) {
tud_task();
+ cdc_task();
TC0->COUNT8.INTFLAG.reg |= TC_INTFLAG_OVF;
}
diff --git a/watch-library/hardware/watch/watch_storage.c b/watch-library/hardware/watch/watch_storage.c
new file mode 100644
index 00000000..6c87be53
--- /dev/null
+++ b/watch-library/hardware/watch/watch_storage.c
@@ -0,0 +1,94 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "watch_storage.h"
+
+#define RWWEE_ADDR_START NVMCTRL_RWW_EEPROM_ADDR
+#define RWWEE_ADDR_END (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES)
+#define NVM_MEMORY ((volatile uint16_t *)FLASH_ADDR)
+
+static bool _is_valid_address(uint32_t addr, uint32_t size) {
+ if ((addr < NVMCTRL_RWW_EEPROM_ADDR) || (addr > (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES))) {
+ return false;
+ }
+ if ((addr + size > (NVMCTRL_RWW_EEPROM_ADDR + NVMCTRL_PAGE_SIZE * NVMCTRL_RWWEE_PAGES))) {
+ return false;
+ }
+
+ return true;
+}
+
+bool watch_storage_read(uint32_t row, uint32_t offset, uint8_t *buffer, uint32_t size) {
+ uint32_t address = RWWEE_ADDR_START + row * NVMCTRL_ROW_SIZE + offset;
+ if (!_is_valid_address(address, size)) return false;
+
+ uint32_t nvm_address = address / 2;
+ uint32_t i;
+ uint16_t data;
+
+ watch_storage_sync();
+
+ if (address % 2) {
+ data = NVM_MEMORY[nvm_address++];
+ buffer[0] = data >> 8;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ while (i < size) {
+ data = NVM_MEMORY[nvm_address++];
+ buffer[i] = (data & 0xFF);
+ if (i < (size - 1)) {
+ buffer[i + 1] = (data >> 8);
+ }
+ i += 2;
+ }
+ return true;
+}
+
+bool watch_storage_write(uint32_t row, uint32_t offset, const uint8_t *buffer, uint32_t size) {
+ uint32_t address = RWWEE_ADDR_START + row * NVMCTRL_ROW_SIZE + offset;
+ if (!_is_valid_address(address, size)) return false;
+
+ watch_storage_sync();
+
+ uint32_t nvm_address = address / 2;
+ uint16_t i, data;
+
+ hri_nvmctrl_write_CTRLA_reg(NVMCTRL, NVMCTRL_CTRLA_CMD_PBC | NVMCTRL_CTRLA_CMDEX_KEY);
+ watch_storage_sync();
+
+ for (i = 0; i < size; i += 2) {
+ data = buffer[i];
+ if (i < NVMCTRL_PAGE_SIZE - 1) {
+ data |= (buffer[i + 1] << 8);
+ }
+ NVM_MEMORY[nvm_address++] = data;
+ }
+ hri_nvmctrl_write_ADDR_reg(NVMCTRL, address / 2);
+ hri_nvmctrl_write_CTRLA_reg(NVMCTRL, NVMCTRL_CTRLA_CMD_RWWEEWP | NVMCTRL_CTRLA_CMDEX_KEY);
+
+ return true;
+}
+
+bool watch_storage_erase(uint32_t row) {
+ uint32_t address = RWWEE_ADDR_START + row * NVMCTRL_ROW_SIZE;
+ if (!_is_valid_address(address, NVMCTRL_ROW_SIZE)) return false;
+
+ watch_storage_sync();
+ hri_nvmctrl_write_ADDR_reg(NVMCTRL, address / 2);
+ hri_nvmctrl_write_CTRLA_reg(NVMCTRL, NVMCTRL_CTRLA_CMD_RWWEEER | NVMCTRL_CTRLA_CMDEX_KEY);
+
+ return true;
+}
+
+bool watch_storage_sync(void) {
+ while (!hri_nvmctrl_get_interrupt_READY_bit(NVMCTRL)) {
+ // wait for flash to become ready
+ }
+
+ hri_nvmctrl_clear_STATUS_reg(NVMCTRL, NVMCTRL_STATUS_MASK);
+
+ return true;
+}