-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
17045: sys/coding: add XOR based coding module r=benpicco a=benpicco 19251: tests/driver_dac_dds: fix output of sine and saw functions r=benpicco a=benpicco 19254: cpu/gd32v: add periph_rtc_mem support r=benpicco a=gschorcht ### Contribution description This PR provides the `periph_rtc_mem` support for GD32VF103. A modified version of this driver could also be used for STM32F1. ### Testing procedure `tests/periph_rtt` should work on any GD32V board, for example: ``` BOARD=sipeed-longan-nano make -C tests/periph_rtt flash ``` ``` Help: Press s to start test, r to print it is ready START main(): This is RIOT! (Version: 2023.04-devel-319-gebc86-cpu/gd32v/periph_rtc_mem) RIOT RTT low-level driver test RTT configuration: RTT_MAX_VALUE: 0xffffffff RTT_FREQUENCY: 32768 Testing the tick conversion Trying to convert 1 to seconds and back Trying to convert 256 to seconds and back Trying to convert 65536 to seconds and back Trying to convert 16777216 to seconds and back Trying to convert 2147483648 to seconds and back All ok Initializing the RTT driver RTC mem OK This test will now display 'Hello' every 5 seconds RTT now: 1 Setting initial alarm to now + 5 s (163841) rtt_get_alarm() PASSED RTC mem OK ``` ### Issues/PRs references Co-authored-by: Benjamin Valentin <benjamin.valentin@ml-pa.com> Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
- Loading branch information
Showing
15 changed files
with
683 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
/* | ||
* Copyright (C) 2023 Gunar Schorcht | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup cpu_gd32v | ||
* @{ | ||
* @file | ||
* @brief Low-level RTC backup memory implementation for GD32VF103 | ||
* | ||
* @author Gunar Schorcht <gunar@schorcht.net> | ||
* @} | ||
*/ | ||
|
||
#include <string.h> | ||
|
||
#include "cpu.h" | ||
#include "periph/rtc_mem.h" | ||
|
||
#define ENABLE_DEBUG 0 | ||
#include "debug.h" | ||
|
||
#define RTC_MEM_SIZE 84 /* RTC data register size in byte */ | ||
|
||
extern void rtc_lock(void); | ||
extern void rtc_unlock(void); | ||
|
||
/* Since the registers are only 16-bit, but 32-bit aligned and not linearly | ||
* addressed, it makes more sense to write and read byte by byte instead of | ||
* using memcpy */ | ||
|
||
static volatile uint16_t *_rtc_mem_data_reg(unsigned addr) | ||
{ | ||
/* This function determines the register address of the 16-bit BKP data | ||
* register which are 32-bit aligned and not addressed linearly. The | ||
* layout is the following: | ||
* | ||
* addr 0, 1, ..., 9 are @0x40006c00 + 0x04, 0x08, ...,0x28 | ||
* addr 10, 11, ..., 41 are @0x40006c00 + 0x40, 0x44, ...,0xbc | ||
*/ | ||
|
||
/* 16-bit data register index */ | ||
unsigned reg_index = addr >> 1; | ||
/* 16-bit data register address as multiple of 32 bit */ | ||
return (reg_index < 10) ? &BKP->DATA0 + (reg_index << 1) | ||
: &BKP->DATA10 + ((reg_index - 10) << 1); | ||
} | ||
|
||
static void _rtc_mem_write_byte(unsigned addr, uint8_t byte) | ||
{ | ||
volatile uint16_t *reg = _rtc_mem_data_reg(addr); | ||
if (addr % 2) { | ||
/* high byte */ | ||
*reg &= 0x00ff; | ||
*reg |= (uint16_t)byte << 8; | ||
} | ||
else { | ||
/* low byte */ | ||
*reg &= 0xff00; | ||
*reg |= byte; | ||
} | ||
} | ||
|
||
static uint8_t _rtc_mem_read_byte(unsigned addr) | ||
{ | ||
volatile uint16_t *reg = _rtc_mem_data_reg(addr); | ||
return (addr % 2) ? (*reg & 0xff00) >> 8 : *reg & 0x00ff; | ||
} | ||
|
||
size_t rtc_mem_size(void) | ||
{ | ||
return RTC_MEM_SIZE; | ||
} | ||
|
||
void rtc_mem_write(unsigned offset, const void *data, size_t len) | ||
{ | ||
assert(offset + len <= rtc_mem_size()); | ||
|
||
/* enable APB1 clocks */ | ||
RCU->APB1EN |= RCU_APB1EN_PMUEN_Msk | RCU_APB1EN_BKPIEN_Msk; | ||
|
||
/* enable write access to backup domain registers */ | ||
PMU->CTL |= PMU_CTL_BKPWEN_Msk; | ||
|
||
for (unsigned i = 0; i < len; i++) { | ||
_rtc_mem_write_byte(offset++, ((uint8_t *)data)[i]); | ||
} | ||
|
||
/* disable write access to backup domain registers */ | ||
PMU->CTL &= ~PMU_CTL_BKPWEN_Msk; | ||
} | ||
|
||
void rtc_mem_read(unsigned offset, void *data, size_t len) | ||
{ | ||
assert(offset + len <= rtc_mem_size()); | ||
|
||
/* enable APB1 clocks */ | ||
RCU->APB1EN |= RCU_APB1EN_PMUEN_Msk | RCU_APB1EN_BKPIEN_Msk; | ||
|
||
for (unsigned i = 0; i < len; i++) { | ||
((uint8_t *)data)[i] = _rtc_mem_read_byte(offset++); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include $(RIOTBASE)/Makefile.base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* | ||
* Copyright (C) 2021 Benjamin Valentin <benjamin.valentin@ml-pa.com> | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @defgroup sys_coding Error correction codes | ||
* @ingroup sys | ||
* @brief Error correction function libraries | ||
* | ||
* This module provides functions to generate redundancy data for error | ||
* correction. | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
/* | ||
* Copyright (C) 2021 Benjamin Valentin <benjamin.valentin@ml-pa.com> | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @ingroup sys_coding_xor | ||
* @brief XOR coding algorithm | ||
* | ||
* @{ | ||
* | ||
* @file | ||
* @brief XOR coding implementation | ||
* | ||
* @author Benjamin Valentin <benjamin.valentin@ml-pa.com> | ||
*/ | ||
|
||
#include <string.h> | ||
#include "bitfield.h" | ||
#include "coding/xor.h" | ||
|
||
#define ENABLE_DEBUG 0 | ||
#include "debug.h" | ||
|
||
static void _gen_parity(const void *data, size_t len, uint8_t *out) | ||
{ | ||
const uint8_t *in = data; | ||
|
||
memset(out, 0, CODING_XOR_PARITY_LEN(len)); | ||
for (unsigned i = 0; i < len; ++i) { | ||
out[i / CONFIG_CODING_XOR_CHECK_BYTES] ^= in[i]; | ||
} | ||
} | ||
|
||
static inline size_t _transpose_idx(size_t i, size_t width, size_t height) | ||
{ | ||
size_t x = i % width; | ||
size_t y = i / width; | ||
|
||
return x * height + y; | ||
} | ||
|
||
static inline void _swap(uint8_t *a, uint8_t *b) | ||
{ | ||
uint8_t tmp = *a; | ||
*a = *b; | ||
*b = tmp; | ||
} | ||
|
||
/* https://www.geeksforgeeks.org/inplace-m-x-n-size-matrix-transpose/ */ | ||
static void _transpose(uint8_t *data, size_t len, size_t height) | ||
{ | ||
BITFIELD(visited, len); | ||
memset(visited, 0, sizeof(visited)); | ||
|
||
/* A[0] and A[size-1] won't move */ | ||
size_t i = 1; | ||
size_t last = len -1; | ||
bf_set(visited, 0); | ||
bf_set(visited, last); | ||
|
||
while (i < last) { | ||
size_t cycle_begin = i; | ||
uint8_t tmp = data[i]; | ||
do { | ||
/* Input matrix [r x c] | ||
* Output matrix | ||
* i_new = (i*r)%(N-1) | ||
*/ | ||
size_t next = (i * height) % last; | ||
_swap(&data[next], &tmp); | ||
bf_set(visited, i); | ||
i = next; | ||
} while (i != cycle_begin); | ||
|
||
/* Get Next Move (what about querying random location?) */ | ||
i = bf_find_first_unset(visited, len); | ||
} | ||
} | ||
|
||
static inline void _mix(void *data, size_t len) | ||
{ | ||
_transpose(data, len, len / CONFIG_CODING_XOR_CHECK_BYTES); | ||
} | ||
|
||
static inline void _unmix(void *data, size_t len) | ||
{ | ||
_transpose(data, len, CONFIG_CODING_XOR_CHECK_BYTES); | ||
} | ||
|
||
static bool _recover_byte(const uint8_t *in, size_t width, uint8_t height, | ||
const uint8_t *parity, size_t idx, uint8_t *bitfield, | ||
size_t block_size, uint8_t *out) | ||
{ | ||
uint8_t res = parity[idx / CONFIG_CODING_XOR_CHECK_BYTES]; | ||
size_t start = idx - idx % CONFIG_CODING_XOR_CHECK_BYTES; | ||
|
||
for (unsigned i = start; i < start + CONFIG_CODING_XOR_CHECK_BYTES; ++i) { | ||
/* skip the lost byte */ | ||
if (i == idx) { | ||
continue; | ||
} | ||
|
||
/* get index of neighbor byte in transposed matrix */ | ||
size_t idx_in = _transpose_idx(i, height, width); | ||
if (!bf_isset(bitfield, idx_in / block_size)) { | ||
DEBUG("missing chunk %u\n", idx_in / block_size); | ||
return false; | ||
} | ||
res ^= in[idx_in]; | ||
} | ||
|
||
*out = res; | ||
return true; | ||
} | ||
|
||
static bool _recover_blocks(void *data, size_t len, const uint8_t *parity, | ||
uint8_t *bitfield, size_t block_size) | ||
{ | ||
uint8_t *in = data; | ||
|
||
const uint8_t height = CONFIG_CODING_XOR_CHECK_BYTES; | ||
const size_t width = len / height; | ||
const uint8_t num_data_blocks = len / block_size; | ||
bool success = true; | ||
|
||
for (size_t i = 0; i < len; i += block_size) { | ||
/* block is present, nothing to do */ | ||
if (bf_isset(bitfield, i / block_size)) { | ||
continue; | ||
} | ||
|
||
DEBUG("try to recover chunk %u / %u\n", i / block_size, num_data_blocks); | ||
for (size_t j = i; j < i + block_size; ++j) { | ||
|
||
/* get original byte position */ | ||
size_t idx = _transpose_idx(j, width, height); | ||
|
||
/* we can only recover the byte if we have the matching parity block */ | ||
size_t parity_block = idx / (CONFIG_CODING_XOR_CHECK_BYTES * block_size); | ||
if (!bf_isset(bitfield, num_data_blocks + parity_block)) { | ||
DEBUG("missing parity block %u\n", parity_block); | ||
success = false; | ||
goto next_block; | ||
} | ||
|
||
/* try to recover lost byte from parity */ | ||
if (!_recover_byte(in, width, height, parity, idx, | ||
bitfield, block_size, &in[j])) { | ||
success = false; | ||
goto next_block; | ||
} | ||
} | ||
bf_set(bitfield, i / block_size); | ||
|
||
next_block: | ||
/* try to recover another block */ ; | ||
} | ||
|
||
return success; | ||
} | ||
|
||
void coding_xor_generate(void *data, size_t len, uint8_t *parity) | ||
{ | ||
_gen_parity(data, len, parity); | ||
_mix(data, len); | ||
} | ||
|
||
bool coding_xor_recover(void *data, size_t len, uint8_t *parity, | ||
uint8_t *bitfield, size_t block_size, bool recover_parity) | ||
{ | ||
size_t num_data_chunks = len / block_size; | ||
size_t num_parity_chunks = CODING_XOR_PARITY_LEN(len) / block_size; | ||
|
||
if (!_recover_blocks(data, len, parity, bitfield, block_size)) { | ||
return false; | ||
} | ||
|
||
_unmix(data, len); | ||
|
||
if (!recover_parity) { | ||
return true; | ||
} | ||
|
||
/* recover lost parity blocks */ | ||
for (size_t i = 0; i < num_parity_chunks; ++i) { | ||
if (bf_isset(bitfield, num_data_chunks + i)) { | ||
continue; | ||
} | ||
|
||
DEBUG("regenerate parity block %u\n", i); | ||
size_t data_len = block_size * CONFIG_CODING_XOR_CHECK_BYTES; | ||
_gen_parity((uint8_t *)data + i * data_len, | ||
data_len, parity + i * block_size); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** @} */ |
Oops, something went wrong.