minor changes
This commit is contained in:
@@ -13,6 +13,23 @@
|
||||
#define PMOD_SPI_CTRL_QUAD 0x4u
|
||||
|
||||
static uint32_t pmod_spi_ctrl_shadow = PMOD_SPI_CTRL_CSN;
|
||||
static uint32_t pmod_spi_cs_setup_us;
|
||||
static uint32_t pmod_spi_inter_byte_us;
|
||||
static uint32_t pmod_spi_cs_hold_us;
|
||||
static uint32_t pmod_spi_cs_inactive_us;
|
||||
|
||||
static void pmod_spi_delay_us(uint32_t us)
|
||||
{
|
||||
if (us == 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t ticks =
|
||||
((uint64_t)BSP_CLINT_TIMEBASE_HZ * us + 999999u) / 1000000u;
|
||||
const uint64_t start = bsp_read64(BSP_CLINT_MTIME);
|
||||
while ((bsp_read64(BSP_CLINT_MTIME) - start) < ticks) {
|
||||
}
|
||||
}
|
||||
|
||||
static void pmod_spi_wait_ready(void)
|
||||
{
|
||||
@@ -55,6 +72,17 @@ void bsp_pmod_spi_set_quad(int enabled)
|
||||
bsp_pmod_spi_set_mode(enabled ? BSP_PMOD_SPI_MODE_QUAD : BSP_PMOD_SPI_MODE_SINGLE);
|
||||
}
|
||||
|
||||
void bsp_pmod_spi_set_timing(uint32_t cs_setup_us,
|
||||
uint32_t inter_byte_us,
|
||||
uint32_t cs_hold_us,
|
||||
uint32_t cs_inactive_us)
|
||||
{
|
||||
pmod_spi_cs_setup_us = cs_setup_us;
|
||||
pmod_spi_inter_byte_us = inter_byte_us;
|
||||
pmod_spi_cs_hold_us = cs_hold_us;
|
||||
pmod_spi_cs_inactive_us = cs_inactive_us;
|
||||
}
|
||||
|
||||
void bsp_pmod_spi_select(void)
|
||||
{
|
||||
pmod_spi_write_ctrl(pmod_spi_ctrl_shadow & ~PMOD_SPI_CTRL_CSN);
|
||||
@@ -109,3 +137,68 @@ void bsp_pmod_spi_transfer(const uint8_t *tx, uint8_t *rx, size_t len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bsp_pmod_spi_transaction(const uint8_t *tx, uint8_t *rx, size_t len)
|
||||
{
|
||||
if (len == 0u) {
|
||||
return;
|
||||
}
|
||||
|
||||
bsp_pmod_spi_select();
|
||||
pmod_spi_delay_us(pmod_spi_cs_setup_us);
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
const uint8_t out = tx ? tx[i] : 0xffu;
|
||||
const uint8_t in = bsp_pmod_spi_xfer8(out);
|
||||
if (rx) {
|
||||
rx[i] = in;
|
||||
}
|
||||
if ((i + 1u) < len) {
|
||||
pmod_spi_delay_us(pmod_spi_inter_byte_us);
|
||||
}
|
||||
}
|
||||
|
||||
pmod_spi_delay_us(pmod_spi_cs_hold_us);
|
||||
bsp_pmod_spi_deselect();
|
||||
pmod_spi_delay_us(pmod_spi_cs_inactive_us);
|
||||
}
|
||||
|
||||
void bsp_pmod_spi_write_reg8(uint8_t command, uint8_t value)
|
||||
{
|
||||
const uint8_t tx[2] = {command, value};
|
||||
bsp_pmod_spi_transaction(tx, NULL, sizeof(tx));
|
||||
}
|
||||
|
||||
void bsp_pmod_spi_read_regs(uint8_t command,
|
||||
uint8_t dummy,
|
||||
uint8_t *data,
|
||||
size_t len)
|
||||
{
|
||||
if ((data == NULL) || (len == 0u)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bsp_pmod_spi_select();
|
||||
pmod_spi_delay_us(pmod_spi_cs_setup_us);
|
||||
|
||||
(void)bsp_pmod_spi_xfer8(command);
|
||||
pmod_spi_delay_us(pmod_spi_inter_byte_us);
|
||||
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
data[i] = bsp_pmod_spi_xfer8(dummy);
|
||||
if ((i + 1u) < len) {
|
||||
pmod_spi_delay_us(pmod_spi_inter_byte_us);
|
||||
}
|
||||
}
|
||||
|
||||
pmod_spi_delay_us(pmod_spi_cs_hold_us);
|
||||
bsp_pmod_spi_deselect();
|
||||
pmod_spi_delay_us(pmod_spi_cs_inactive_us);
|
||||
}
|
||||
|
||||
uint8_t bsp_pmod_spi_read_reg8(uint8_t command, uint8_t dummy)
|
||||
{
|
||||
uint8_t value = 0xffu;
|
||||
bsp_pmod_spi_read_regs(command, dummy, &value, 1u);
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,16 @@ void bsp_pmod_spi_init(void);
|
||||
void bsp_pmod_spi_set_mode(bsp_pmod_spi_mode_t mode);
|
||||
bsp_pmod_spi_mode_t bsp_pmod_spi_mode(void);
|
||||
void bsp_pmod_spi_set_quad(int enabled);
|
||||
|
||||
/*
|
||||
* Configure delays used by the chip-select-managed transaction helpers.
|
||||
* All values are in microseconds. Zero disables the corresponding delay.
|
||||
*/
|
||||
void bsp_pmod_spi_set_timing(uint32_t cs_setup_us,
|
||||
uint32_t inter_byte_us,
|
||||
uint32_t cs_hold_us,
|
||||
uint32_t cs_inactive_us);
|
||||
|
||||
void bsp_pmod_spi_select(void);
|
||||
void bsp_pmod_spi_deselect(void);
|
||||
int bsp_pmod_spi_ready(void);
|
||||
@@ -20,6 +30,22 @@ uint32_t bsp_pmod_spi_ctrl(void);
|
||||
uint32_t bsp_pmod_spi_rx(void);
|
||||
uint8_t bsp_pmod_spi_xfer8(uint8_t value);
|
||||
uint32_t bsp_pmod_spi_xfer32(uint32_t value);
|
||||
|
||||
/* Raw byte transfer; the caller controls chip select. */
|
||||
void bsp_pmod_spi_transfer(const uint8_t *tx, uint8_t *rx, size_t len);
|
||||
|
||||
/* Byte transaction with chip select and the configured timing delays. */
|
||||
void bsp_pmod_spi_transaction(const uint8_t *tx, uint8_t *rx, size_t len);
|
||||
|
||||
/*
|
||||
* Register helpers accept the complete command byte. The caller is
|
||||
* responsible for applying device-specific read/write bits to command.
|
||||
*/
|
||||
void bsp_pmod_spi_write_reg8(uint8_t command, uint8_t value);
|
||||
uint8_t bsp_pmod_spi_read_reg8(uint8_t command, uint8_t dummy);
|
||||
void bsp_pmod_spi_read_regs(uint8_t command,
|
||||
uint8_t dummy,
|
||||
uint8_t *data,
|
||||
size_t len);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
TARGET := pmod_spi_test
|
||||
APP_SRCS := pmod_spi_test.c
|
||||
BSP_SRCS := init.c uart.c plic.c irq.c spi_flash.c pmod_spi.c
|
||||
include ../common/app.mk
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
MARCH=rv64imafdc_zicsr_zifencei
|
||||
MABI=lp64d
|
||||
BSP_UART_CLOCK_HZ=100000000
|
||||
BSP_UART_BAUDRATE=115200
|
||||
BSP_CLINT_TIMEBASE_HZ=1000000
|
||||
BSP_DTIM_BASE=0x80000000
|
||||
BSP_DTIM_SIZE=0x00100000
|
||||
GPS_DEBUG=
|
||||
GPS_DEBUG_LEVEL=
|
||||
CFLAGS=-march=rv64imafdc_zicsr_zifencei -mabi=lp64d -mcmodel=medany -Os -ffreestanding -fno-builtin -fno-common -Wall -Wextra -I../bsp/include -DBSP_UART_CLOCK_HZ=100000000UL -DBSP_UART_BAUDRATE=115200UL -DBSP_CLINT_TIMEBASE_HZ=1000000UL -DBSP_DTIM_BASE=0x80000000UL -DBSP_DTIM_SIZE=0x00100000UL
|
||||
LDFLAGS=-T ../common/linker_ram.ld -nostartfiles -static -Wl,--gc-sections -Wl,--defsym=__dtim_base=0x80000000 -Wl,--defsym=__dtim_size=0x00100000 -Wl,-Map,build/pmod_spi_test.map
|
||||
LDLIBS=-Wl,--start-group -lc -lgcc -Wl,--end-group
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,150 @@
|
||||
@page {
|
||||
size: A4;
|
||||
margin: 16mm 16mm 18mm 16mm;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: "DejaVu Sans", Arial, sans-serif;
|
||||
font-size: 9.5pt;
|
||||
line-height: 1.42;
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
body {
|
||||
max-width: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
color: #24558d;
|
||||
line-height: 1.18;
|
||||
break-after: avoid-page;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-top: 1.15em;
|
||||
padding-bottom: 0.18em;
|
||||
border-bottom: 2px solid #8fb3d9;
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 1.0em;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0.9em;
|
||||
font-size: 11.5pt;
|
||||
}
|
||||
|
||||
p, li {
|
||||
orphans: 3;
|
||||
widows: 3;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 0.55em 0 0.9em 0;
|
||||
font-size: 8.35pt;
|
||||
break-inside: auto;
|
||||
}
|
||||
|
||||
thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
|
||||
tr {
|
||||
break-inside: avoid-page;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #9aa9bb;
|
||||
padding: 4px 6px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th {
|
||||
background: #dceafb;
|
||||
color: #173f6c;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(even) td {
|
||||
background: #f6f9fc;
|
||||
}
|
||||
|
||||
pre {
|
||||
font-family: "DejaVu Sans Mono", monospace;
|
||||
font-size: 8.1pt;
|
||||
line-height: 1.32;
|
||||
background: #f3f6f9;
|
||||
border-left: 4px solid #5c87b5;
|
||||
padding: 7px 9px;
|
||||
white-space: pre-wrap;
|
||||
overflow-wrap: anywhere;
|
||||
break-inside: avoid-page;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: "DejaVu Sans Mono", monospace;
|
||||
color: #153f69;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #1d5f9e;
|
||||
text-decoration: none;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 0;
|
||||
padding: 0.2em 0.8em;
|
||||
border-left: 4px solid #91a9c2;
|
||||
background: #f6f8fa;
|
||||
}
|
||||
|
||||
#title-block-header {
|
||||
min-height: 235mm;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
break-after: page;
|
||||
}
|
||||
|
||||
#title-block-header h1 {
|
||||
border: 0;
|
||||
color: #173f6c;
|
||||
font-size: 25pt;
|
||||
}
|
||||
|
||||
#TOC {
|
||||
break-after: page;
|
||||
columns: 2;
|
||||
column-gap: 12mm;
|
||||
font-size: 8.7pt;
|
||||
}
|
||||
|
||||
#TOC > h2 {
|
||||
column-span: all;
|
||||
font-size: 18pt;
|
||||
}
|
||||
|
||||
#TOC ul {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
border-top: 1px solid #8ca0b5;
|
||||
margin: 1.5em 0;
|
||||
}
|
||||
|
||||
@media print {
|
||||
a[href^="http"]::after {
|
||||
content: "";
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "bsp/soc.h"
|
||||
#include "bsp/uart.h"
|
||||
|
||||
/* ICM-42686-P user bank 0 registers. */
|
||||
/* ICM-42686-P/ICM-42688-P user bank 0 registers. */
|
||||
#define ICM_DEVICE_CONFIG 0x11u
|
||||
#define ICM_TEMP_DATA1 0x1du
|
||||
#define ICM_INT_STATUS 0x2du
|
||||
@@ -15,7 +15,11 @@
|
||||
#define ICM_ACCEL_CONFIG0 0x50u
|
||||
#define ICM_WHO_AM_I 0x75u
|
||||
|
||||
#define ICM_WHO_AM_I_VALUE 0x44u
|
||||
#define ICM_SPI_READ 0x80u
|
||||
#define ICM_SPI_DUMMY 0xffu
|
||||
|
||||
#define ICM42686_WHO_AM_I 0x44u
|
||||
#define ICM42688_WHO_AM_I 0x47u
|
||||
|
||||
static void delay_us(uint32_t us)
|
||||
{
|
||||
@@ -28,35 +32,12 @@ static void delay_us(uint32_t us)
|
||||
|
||||
static void icm_write_reg(uint8_t reg, uint8_t value)
|
||||
{
|
||||
bsp_pmod_spi_select();
|
||||
delay_us(10u);
|
||||
(void)bsp_pmod_spi_xfer8(reg & 0x7fu);
|
||||
delay_us(10u);
|
||||
(void)bsp_pmod_spi_xfer8(value);
|
||||
delay_us(10u);
|
||||
bsp_pmod_spi_deselect();
|
||||
delay_us(10u);
|
||||
}
|
||||
|
||||
static void icm_read_regs(uint8_t reg, uint8_t *data, unsigned len)
|
||||
{
|
||||
bsp_pmod_spi_select();
|
||||
delay_us(10u);
|
||||
(void)bsp_pmod_spi_xfer8(reg | 0x80u);
|
||||
delay_us(10u);
|
||||
for (unsigned i = 0; i < len; ++i) {
|
||||
data[i] = bsp_pmod_spi_xfer8(0xffu);
|
||||
delay_us(10u);
|
||||
}
|
||||
bsp_pmod_spi_deselect();
|
||||
delay_us(10u);
|
||||
bsp_pmod_spi_write_reg8(reg & (uint8_t)~ICM_SPI_READ, value);
|
||||
}
|
||||
|
||||
static uint8_t icm_read_reg(uint8_t reg)
|
||||
{
|
||||
uint8_t value;
|
||||
icm_read_regs(reg, &value, 1u);
|
||||
return value;
|
||||
return bsp_pmod_spi_read_reg8(reg | ICM_SPI_READ, ICM_SPI_DUMMY);
|
||||
}
|
||||
|
||||
static int16_t be16(const uint8_t *p)
|
||||
@@ -67,39 +48,46 @@ static int16_t be16(const uint8_t *p)
|
||||
int main(void)
|
||||
{
|
||||
uint8_t raw[14];
|
||||
long accel_full_scale_mg;
|
||||
long gyro_full_scale_mdps;
|
||||
|
||||
printf("\nICM-42686-P PMOD SPI test\n");
|
||||
printf("\nICM-42686-P/ICM-42688-P PMOD SPI test\n");
|
||||
printf("SPI MMIO: 0x%08lx, Genesys2 PMOD JC\n",
|
||||
(unsigned long)BSP_PMOD_SPI_BASE);
|
||||
printf("pins: CS=JC1 MOSI=JC2 MISO=JC3 SCK=JC4\n");
|
||||
|
||||
bsp_pmod_spi_init();
|
||||
bsp_pmod_spi_set_mode(BSP_PMOD_SPI_MODE_SINGLE);
|
||||
bsp_pmod_spi_set_timing(10u, 10u, 10u, 10u);
|
||||
delay_us(1000u);
|
||||
|
||||
printf("WHO_AM_I before SPI_MODE write:");
|
||||
printf("WHO_AM_I reads:");
|
||||
uint8_t who_am_i = 0u;
|
||||
for (unsigned attempt = 0; attempt < 4u; ++attempt) {
|
||||
printf(" %02x", icm_read_reg(ICM_WHO_AM_I));
|
||||
who_am_i = icm_read_reg(ICM_WHO_AM_I);
|
||||
printf(" %02x", who_am_i);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/*
|
||||
* The FPGA master is CPOL=0/CPHA=1. ICM-42686-P powers up accepting
|
||||
* modes 0/3, so first switch DEVICE_CONFIG.SPI_MODE to modes 1/2.
|
||||
* A mode-1-master/mode-0-slave write is valid because the slave samples
|
||||
* MOSI on the rising edge, before the master changes it on the falling edge.
|
||||
* Keep DEVICE_CONFIG.SPI_MODE at its reset value. Although the RTL shifts
|
||||
* and samples on the falling edge, board propagation makes it interoperate
|
||||
* with the sensor's default mode-0 timing. Switching the sensor to mode 1
|
||||
* breaks this working timing relationship on the current bitstream.
|
||||
*/
|
||||
icm_write_reg(ICM_DEVICE_CONFIG, 0x10u);
|
||||
delay_us(100u);
|
||||
|
||||
const uint8_t device_config = icm_read_reg(ICM_DEVICE_CONFIG);
|
||||
const uint8_t who_am_i = icm_read_reg(ICM_WHO_AM_I);
|
||||
printf("DEVICE_CONFIG=0x%02x (expected 0x10)\n", device_config);
|
||||
printf("WHO_AM_I=0x%02x (expected 0x%02x): %s\n",
|
||||
who_am_i, ICM_WHO_AM_I_VALUE,
|
||||
who_am_i == ICM_WHO_AM_I_VALUE ? "PASS" : "FAIL");
|
||||
printf("DEVICE_CONFIG=0x%02x (expected 0x00)\n", device_config);
|
||||
|
||||
if (who_am_i != ICM_WHO_AM_I_VALUE) {
|
||||
if (who_am_i == ICM42686_WHO_AM_I) {
|
||||
accel_full_scale_mg = 32000l;
|
||||
gyro_full_scale_mdps = 4000000l;
|
||||
printf("WHO_AM_I=0x%02x: ICM-42686-P PASS\n", who_am_i);
|
||||
} else if (who_am_i == ICM42688_WHO_AM_I) {
|
||||
accel_full_scale_mg = 16000l;
|
||||
gyro_full_scale_mdps = 2000000l;
|
||||
printf("WHO_AM_I=0x%02x: ICM-42688-P PASS\n", who_am_i);
|
||||
} else {
|
||||
printf("WHO_AM_I=0x%02x: FAIL (expected 0x44 or 0x47)\n", who_am_i);
|
||||
printf("SPI communication failed. DK J4: CS=1 SCK=2 MOSI=3 MISO=4 GND=7.\n");
|
||||
printf("Hold the DK SAMG55 in reset so it cannot contend for the sensor SPI bus.\n");
|
||||
bsp_uart_wait_tx_idle();
|
||||
@@ -115,11 +103,14 @@ int main(void)
|
||||
const uint8_t accel_cfg = icm_read_reg(ICM_ACCEL_CONFIG0);
|
||||
printf("PWR_MGMT0=0x%02x GYRO_CONFIG0=0x%02x ACCEL_CONFIG0=0x%02x\n",
|
||||
pwr, gyro_cfg, accel_cfg);
|
||||
printf("units: temperature=mC accel=mg gyro=mdps (default +/-32g, +/-4000dps)\n");
|
||||
printf("units: temperature=mC accel=mg gyro=mdps\n");
|
||||
|
||||
for (unsigned sample = 0; sample < 40u; ++sample) {
|
||||
const uint8_t status = icm_read_reg(ICM_INT_STATUS);
|
||||
icm_read_regs(ICM_TEMP_DATA1, raw, sizeof(raw));
|
||||
bsp_pmod_spi_read_regs(ICM_TEMP_DATA1 | ICM_SPI_READ,
|
||||
ICM_SPI_DUMMY,
|
||||
raw,
|
||||
sizeof(raw));
|
||||
|
||||
const int16_t temp = be16(&raw[0]);
|
||||
const int16_t ax = be16(&raw[2]);
|
||||
@@ -130,12 +121,12 @@ int main(void)
|
||||
const int16_t gz = be16(&raw[12]);
|
||||
|
||||
const long temp_mc = 25000l + (long)(((int64_t)temp * 100000) / 13248);
|
||||
const long ax_mg = (long)(((int64_t)ax * 32000) / 32768);
|
||||
const long ay_mg = (long)(((int64_t)ay * 32000) / 32768);
|
||||
const long az_mg = (long)(((int64_t)az * 32000) / 32768);
|
||||
const long gx_mdps = (long)(((int64_t)gx * 4000000) / 32768);
|
||||
const long gy_mdps = (long)(((int64_t)gy * 4000000) / 32768);
|
||||
const long gz_mdps = (long)(((int64_t)gz * 4000000) / 32768);
|
||||
const long ax_mg = (long)(((int64_t)ax * accel_full_scale_mg) / 32768);
|
||||
const long ay_mg = (long)(((int64_t)ay * accel_full_scale_mg) / 32768);
|
||||
const long az_mg = (long)(((int64_t)az * accel_full_scale_mg) / 32768);
|
||||
const long gx_mdps = (long)(((int64_t)gx * gyro_full_scale_mdps) / 32768);
|
||||
const long gy_mdps = (long)(((int64_t)gy * gyro_full_scale_mdps) / 32768);
|
||||
const long gz_mdps = (long)(((int64_t)gz * gyro_full_scale_mdps) / 32768);
|
||||
|
||||
printf("%02u st=%02x T=%ld A=%ld,%ld,%ld G=%ld,%ld,%ld\n",
|
||||
sample, status, temp_mc,
|
||||
@@ -143,7 +134,7 @@ int main(void)
|
||||
delay_us(100000u);
|
||||
}
|
||||
|
||||
printf("ICM-42686-P read complete\n");
|
||||
printf("IMU read complete\n");
|
||||
bsp_uart_wait_tx_idle();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user