Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion boards/hifive1/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FEATURES_PROVIDED += periph_gpio periph_gpio_irq
#FEATURES_PROVIDED += periph_pwm
FEATURES_PROVIDED += periph_rtc
FEATURES_PROVIDED += periph_rtt
#FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_spi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be applied to the hifive1b (I can test on this board actually).

FEATURES_PROVIDED += periph_timer
FEATURES_PROVIDED += periph_uart

Expand Down
28 changes: 22 additions & 6 deletions boards/hifive1/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif
Expand All @@ -27,12 +29,8 @@ extern "C" {
* @name Core Clock configuration
* @{
*/
#define CLOCK_CORECLOCK (1600000ul)
/*
* #define CLOCK_CORECLOCK (20000000ul)
* #define CLOCK_CORECLOCK (27000000ul)
* #define CLOCK_CORECLOCK (38400000ul)
*/
/* As defined in boards/hifive1/board.c CPU_DESIRED_FREQ **/
#define CLOCK_CORECLOCK (200000000ul)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might be interested by #12934 where the value of the core clock is automatically computed when using the PLL or HFXOSC.
Maybe rebase this PR on top of it ?

/** @} */

/**
Expand Down Expand Up @@ -82,6 +80,24 @@ extern "C" {
#define PWM_NUMOF (3)
/** @} */

/**
* @name SPI device configuration
*
* @{
*/
/* DIV_UP is division which rounds up instead of down */
#define DIV_UP(a,b) (((a) + ((b) - 1)) / (b))
static const uint32_t spi_clk_config[] = {
DIV_UP(CLOCK_CORECLOCK, 2 * 100000) - 1,
DIV_UP(CLOCK_CORECLOCK, 2 * 400000) - 1,
DIV_UP(CLOCK_CORECLOCK, 2 * 1000000) - 1,
DIV_UP(CLOCK_CORECLOCK, 2 * 5000000) - 1,
DIV_UP(CLOCK_CORECLOCK, 2 * 10000000) - 1,
};
#undef DIV_UP
#define SPI_NUMOF (1)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to have some struct based configuration. See #12917 where I changed the UART to use this scheme. I find this convenient, at least to know which pins are connected the serial interface and it's more consistent with most of other board configurations in RIOT (like STM, SAM, nRF).

/** @} */

/**
* @name UART configuration
*
Expand Down
4 changes: 4 additions & 0 deletions cpu/fe310/Makefile.include
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ USEMODULE += newlib_syscalls_fe310
USEMODULE += sifive_drivers_fe310

USEMODULE += periph
USEMODULE += periph_common

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, just remove it.

USEMODULE += periph_pm

# include common periph drivers
USEMODULE += periph_common

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

periph_common is added twice

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyway, this is not needed, so just remove it.


CFLAGS += -Wno-pedantic

include $(RIOTMAKE)/arch/riscv.inc.mk
4 changes: 4 additions & 0 deletions cpu/fe310/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "cpu.h"
#include "context_frame.h"
#include "periph_cpu.h"
#include "periph/init.h"
#include "panic.h"
#include "vendor/encoding.h"
#include "vendor/platform.h"
Expand Down Expand Up @@ -88,6 +89,9 @@ void cpu_init(void)

/* Set default state of mstatus */
set_csr(mstatus, MSTATUS_DEFAULT);

/* trigger static peripheral initialization */
periph_init();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is already in master. Maybe just rebase this PR so this change is dropped from GitHub diff ?

}

/**
Expand Down
9 changes: 9 additions & 0 deletions cpu/fe310/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ extern "C" {
*/
#define CPUID_LEN (12U)

/**
* @name This CPU makes use of the following shared SPI functions
* @{
*/
#define PERIPH_SPI_NEEDS_TRANSFER_BYTE 1
#define PERIPH_SPI_NEEDS_TRANSFER_REG 1
#define PERIPH_SPI_NEEDS_TRANSFER_REGS 1
/** @} */

/**
* @brief Prevent shared timer functions from being used
*/
Expand Down
137 changes: 137 additions & 0 deletions cpu/fe310/periph/spi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Copyright (C) 2019 Tristan Bruns
*
* 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_fe310
* @ingroup drivers_periph_spi
*
* @{
*
* @file spi.c
* @brief Low-level SPI driver implementation
*
* @author Tristan Bruns
*
* @}
*/

#include "cpu.h"
#include "mutex.h"
#include "assert.h"
#include "periph/spi.h"
#include "vendor/platform.h"

#define ENABLE_DEBUG (0)
#include "debug.h"

/**
* @brief Allocation device locks
*/
static mutex_t lock;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would make sharing the code with future versions of the CPU that could potentially have multiple SPI interface easier when you use something like that:

#define SPI_INTERFACE_NUM         1
static mutex_t lock[SPI_INTERFACE_NUM];

(I'm only suggesting this, not insisting on this.)


void spi_init(spi_t bus)
{
/* make sure given bus device is valid */
assert(bus == 0);

/* initialize the buses lock */
mutex_init(&lock);

/* trigger pin initialization */
spi_init_pins(bus);

/* disable hardware chip select
(hardware chip select only supports one-byte transfers...) */
SPI1_REG(SPI_REG_CSMODE) = SPI_CSMODE_OFF;
}

void spi_init_pins(spi_t bus)
{
(void) bus;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not needed because of the assert(bus == 0); below. (I believe both GCC and clang should still be aware that bus was used even when NDEBUG is defined, but I'm not 100% sure about that. So please correct me if I'm wrong.)

assert(bus == 0);

const gpio_t spi1_pins =
(1 << IOF_SPI1_MOSI) |
(1 << IOF_SPI1_MISO) |
(1 << IOF_SPI1_SCK);

/* Enable I/O Function 0 */
GPIO_REG(GPIO_IOF_EN) |= spi1_pins;
GPIO_REG(GPIO_IOF_SEL) &= ~spi1_pins;
}

int spi_init_cs(spi_t bus, spi_cs_t cs)
{
if (bus != 0) {
return SPI_NODEV;
}

/* setting the CS high before configuring it as an
output should be fine on FE310. */
gpio_set(cs);

if (gpio_init(cs, GPIO_OUT)) {
return SPI_NOCS;
}

return SPI_OK;
}

int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk)
{
(void) bus;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would make life easier to also add assert()s for bus and cs here, so that developers are supported in finding their bugs in using the SPI interface.

(void) cs;

mutex_lock(&lock);

SPI1_REG(SPI_REG_SCKDIV) = spi_clk_config[clk];
SPI1_REG(SPI_REG_SCKMODE) = mode;

return SPI_OK;
}

void spi_release(spi_t bus)
{
(void) bus;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I would suggest to add an assert()


mutex_unlock(&lock);
}

void spi_transfer_bytes(spi_t bus, spi_cs_t cs, bool cont,
const void *out_, void *in_, size_t len)
{
(void) bus;

assert((out_ || in_) && len > 0);
assert(SPI1_REG(SPI_REG_RXFIFO) & SPI_RXFIFO_EMPTY);
assert(!(SPI1_REG(SPI_REG_TXFIFO) & SPI_TXFIFO_FULL));

const uint8_t *out = out_;
uint8_t *in = in_;

if (cs != SPI_CS_UNDEF) {
gpio_clear(cs);
}

for (size_t i = 0; i < len; i++) {
SPI1_REG(SPI_REG_TXFIFO) = out ? out[i] : 0;

uint32_t rxdata = SPI_RXFIFO_EMPTY;
while (rxdata & SPI_RXFIFO_EMPTY) {
rxdata = SPI1_REG(SPI_REG_RXFIFO);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about

uint32_t rxdata;
do {
    rxdata = SPI1_REG(SPI_REG_RXFIFO);
} while (rxdata & SPI_RXFIFO_EMPTY);


if (in) {
in[i] = (uint8_t)rxdata;
}
}

if (cs != SPI_CS_UNDEF && !cont) {
gpio_set(cs);
}
}