-
Notifications
You must be signed in to change notification settings - Fork 2.1k
cpu/fe310, board/hifive1: SPI support #10833
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,8 @@ | |
| #ifndef PERIPH_CONF_H | ||
| #define PERIPH_CONF_H | ||
|
|
||
| #include <stdint.h> | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
@@ -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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| /** @} */ | ||
|
|
||
| /** | ||
|
|
@@ -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) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,8 +5,12 @@ USEMODULE += newlib_syscalls_fe310 | |
| USEMODULE += sifive_drivers_fe310 | ||
|
|
||
| USEMODULE += periph | ||
| USEMODULE += periph_common | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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" | ||
|
|
@@ -88,6 +89,9 @@ void cpu_init(void) | |
|
|
||
| /* Set default state of mstatus */ | ||
| set_csr(mstatus, MSTATUS_DEFAULT); | ||
|
|
||
| /* trigger static peripheral initialization */ | ||
| periph_init(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 ? |
||
| } | ||
|
|
||
| /** | ||
|
|
||
| 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; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should not needed because of the |
||
| 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; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would make life easier to also add |
||
| (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; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again I would suggest to add an |
||
|
|
||
| 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); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
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).