Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
3 people authored Feb 7, 2023
4 parents 304245b + 663678c + 65fccdd + dc5a1e9 commit c9df5fd
Show file tree
Hide file tree
Showing 15 changed files with 683 additions and 16 deletions.
1 change: 1 addition & 0 deletions cpu/gd32v/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ config CPU_FAM_GD32V
select HAS_PERIPH_FLASHPAGE_PAGEWISE
select HAS_PERIPH_PM
select HAS_PERIPH_RTC
select HAS_PERIPH_RTC_MEM
select HAS_PERIPH_RTT
select HAS_PERIPH_TIMER
select HAS_PERIPH_TIMER_PERIODIC
Expand Down
1 change: 1 addition & 0 deletions cpu/gd32v/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ FEATURES_PROVIDED += periph_clic
FEATURES_PROVIDED += periph_gpio
FEATURES_PROVIDED += periph_gpio_irq
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtc_mem
FEATURES_PROVIDED += periph_rtt
FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_timer_periodic
Expand Down
107 changes: 107 additions & 0 deletions cpu/gd32v/periph/rtc_mem.c
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++);
}
}
4 changes: 4 additions & 0 deletions sys/Makefile.dep
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ ifneq (,$(filter auto_init_sock_dns,$(USEMODULE)))
endif
endif

ifneq (,$(filter coding,$(USEMODULE)))
USEMODULE += bitfield
endif

ifneq (,$(filter congure_%,$(USEMODULE)))
USEMODULE += congure
endif
Expand Down
1 change: 1 addition & 0 deletions sys/coding/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base
16 changes: 16 additions & 0 deletions sys/coding/doc.txt
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.
*/
203 changes: 203 additions & 0 deletions sys/coding/xor.c
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;
}

/** @} */
Loading

0 comments on commit c9df5fd

Please sign in to comment.