max2771 spi liens has been added.
This commit is contained in:
@@ -26,7 +26,7 @@ OBJCOPY := $(CROSS)objcopy
|
||||
READELF := $(CROSS)readelf
|
||||
MAKE_FLASH_IMAGE := $(SOC_DIR)/software/tools/make_flash_image.py
|
||||
|
||||
.PHONY: help all app bootloader hello pmod-spi-test steval-mki217v1-test gps-system flash-image clean
|
||||
.PHONY: help all app bootloader hello pmod-spi-test max2771-spi-test steval-mki217v1-test gps-system flash-image clean
|
||||
|
||||
help:
|
||||
@echo "Common Rocket bare-metal software targets:"
|
||||
@@ -35,6 +35,7 @@ help:
|
||||
@echo " make bootloader # build only BootROM flash bootloader"
|
||||
@echo " make hello # build only hello UART app"
|
||||
@echo " make pmod-spi-test # build PMOD SPI smoke test app"
|
||||
@echo " make max2771-spi-test # build dedicated MAX2771 SPI test app"
|
||||
@echo " make steval-mki217v1-test # build STEVAL-MKI217V1 LSM6DSOX polling app"
|
||||
@echo " make gps-system # build imported GPS bare-metal app"
|
||||
@echo " make flash-image APP=name # build bootloader-readable app flash image"
|
||||
@@ -63,6 +64,9 @@ hello:
|
||||
pmod-spi-test:
|
||||
@make -C pmod_spi_test TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/pmod_spi_test" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
||||
|
||||
max2771-spi-test:
|
||||
@make -C max2771_spi_test TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/max2771_spi_test" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
||||
|
||||
steval-mki217v1-test:
|
||||
@make -C steval_mki217v1_test TOOLCHAIN="$(TOOLCHAIN)" BUILD_DIR="$(OUT_DIR)/steval_mki217v1_test" BSP_UART_CLOCK_HZ="$(BSP_UART_CLOCK_HZ)" BSP_UART_BAUDRATE="$(BSP_UART_BAUDRATE)" BSP_CLINT_TIMEBASE_HZ="$(BSP_CLINT_TIMEBASE_HZ)" BSP_DTIM_BASE="$(BSP_DTIM_BASE)" BSP_DTIM_SIZE="$(BSP_DTIM_SIZE)" all
|
||||
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
#include "bsp/max2771_spi.h"
|
||||
|
||||
#include "bsp/mmio.h"
|
||||
#include "bsp/soc.h"
|
||||
|
||||
#define MAX2771_COMMAND (BSP_MAX2771_SPI_BASE + 0x00u)
|
||||
#define MAX2771_WRITE_DATA (BSP_MAX2771_SPI_BASE + 0x04u)
|
||||
#define MAX2771_READ_DATA (BSP_MAX2771_SPI_BASE + 0x08u)
|
||||
#define MAX2771_STATUS (BSP_MAX2771_SPI_BASE + 0x0cu)
|
||||
#define MAX2771_INPUT_CLOCK (BSP_MAX2771_SPI_BASE + 0x10u)
|
||||
#define MAX2771_SCLK (BSP_MAX2771_SPI_BASE + 0x14u)
|
||||
#define MAX2771_HALF_PERIOD (BSP_MAX2771_SPI_BASE + 0x18u)
|
||||
#define MAX2771_IDENT (BSP_MAX2771_SPI_BASE + 0x1cu)
|
||||
|
||||
#define MAX2771_STATUS_READY 0x1u
|
||||
#define MAX2771_STATUS_BUSY 0x2u
|
||||
#define MAX2771_COMMAND_READ 0x100u
|
||||
#define MAX2771_IDENT_VALUE 0x4d415831u
|
||||
#define MAX2771_TIMEOUT_US 1000u
|
||||
|
||||
static bsp_max2771_status_t max2771_wait_ready(void)
|
||||
{
|
||||
uint64_t timeout_ticks =
|
||||
((uint64_t)BSP_CLINT_TIMEBASE_HZ * MAX2771_TIMEOUT_US + 999999u) /
|
||||
1000000u;
|
||||
if (timeout_ticks == 0u) {
|
||||
timeout_ticks = 1u;
|
||||
}
|
||||
|
||||
const uint64_t start = bsp_read64(BSP_CLINT_MTIME);
|
||||
while ((bsp_read32(MAX2771_STATUS) & MAX2771_STATUS_READY) == 0u) {
|
||||
if ((bsp_read64(BSP_CLINT_MTIME) - start) >= timeout_ticks) {
|
||||
return BSP_MAX2771_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
return BSP_MAX2771_OK;
|
||||
}
|
||||
|
||||
uint32_t bsp_max2771_status(void)
|
||||
{
|
||||
return bsp_read32(MAX2771_STATUS);
|
||||
}
|
||||
|
||||
uint32_t bsp_max2771_input_clock_hz(void)
|
||||
{
|
||||
return bsp_read32(MAX2771_INPUT_CLOCK);
|
||||
}
|
||||
|
||||
uint32_t bsp_max2771_sclk_hz(void)
|
||||
{
|
||||
return bsp_read32(MAX2771_SCLK);
|
||||
}
|
||||
|
||||
uint32_t bsp_max2771_half_period_cycles(void)
|
||||
{
|
||||
return bsp_read32(MAX2771_HALF_PERIOD);
|
||||
}
|
||||
|
||||
bsp_max2771_status_t bsp_max2771_spi_init(void)
|
||||
{
|
||||
if (bsp_read32(MAX2771_IDENT) != MAX2771_IDENT_VALUE) {
|
||||
return BSP_MAX2771_ERR_IP;
|
||||
}
|
||||
|
||||
const uint32_t input_hz = bsp_max2771_input_clock_hz();
|
||||
const uint32_t sclk_hz = bsp_max2771_sclk_hz();
|
||||
const uint32_t half_cycles = bsp_max2771_half_period_cycles();
|
||||
if ((input_hz == 0u) || (half_cycles == 0u) ||
|
||||
(sclk_hz == 0u) || (sclk_hz > BSP_MAX2771_MAX_SCLK_HZ) ||
|
||||
(sclk_hz != (input_hz / (2u * half_cycles)))) {
|
||||
return BSP_MAX2771_ERR_CLOCK;
|
||||
}
|
||||
#ifdef BSP_MAX2771_INPUT_CLOCK_HZ
|
||||
if (input_hz != (uint32_t)BSP_MAX2771_INPUT_CLOCK_HZ) {
|
||||
return BSP_MAX2771_ERR_CLOCK;
|
||||
}
|
||||
#endif
|
||||
|
||||
return max2771_wait_ready();
|
||||
}
|
||||
|
||||
bsp_max2771_status_t bsp_max2771_write(uint8_t address, uint32_t value)
|
||||
{
|
||||
if (address > BSP_MAX2771_MAX_REGISTER) {
|
||||
return BSP_MAX2771_ERR_ARGUMENT;
|
||||
}
|
||||
|
||||
bsp_max2771_status_t status = max2771_wait_ready();
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
bsp_write32(MAX2771_WRITE_DATA, value);
|
||||
bsp_write32(MAX2771_COMMAND, (uint32_t)address);
|
||||
return max2771_wait_ready();
|
||||
}
|
||||
|
||||
bsp_max2771_status_t bsp_max2771_read(uint8_t address, uint32_t *value)
|
||||
{
|
||||
if ((address > BSP_MAX2771_MAX_REGISTER) || (value == 0)) {
|
||||
return BSP_MAX2771_ERR_ARGUMENT;
|
||||
}
|
||||
|
||||
bsp_max2771_status_t status = max2771_wait_ready();
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
bsp_write32(MAX2771_COMMAND, MAX2771_COMMAND_READ | (uint32_t)address);
|
||||
status = max2771_wait_ready();
|
||||
if (status == BSP_MAX2771_OK) {
|
||||
*value = bsp_read32(MAX2771_READ_DATA);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bsp_max2771_status_t bsp_max2771_write_verified(uint8_t address, uint32_t value)
|
||||
{
|
||||
bsp_max2771_status_t status = bsp_max2771_write(address, value);
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t readback = 0u;
|
||||
status = bsp_max2771_read(address, &readback);
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return status;
|
||||
}
|
||||
return (readback == value) ? BSP_MAX2771_OK : BSP_MAX2771_ERR_VERIFY;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef BSP_MAX2771_SPI_H
|
||||
#define BSP_MAX2771_SPI_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define BSP_MAX2771_REGISTER_COUNT 11u
|
||||
#define BSP_MAX2771_MAX_REGISTER 0x0au
|
||||
#define BSP_MAX2771_MAX_SCLK_HZ 4000000u
|
||||
|
||||
typedef enum {
|
||||
BSP_MAX2771_OK = 0,
|
||||
BSP_MAX2771_ERR_ARGUMENT = -1,
|
||||
BSP_MAX2771_ERR_TIMEOUT = -2,
|
||||
BSP_MAX2771_ERR_IP = -3,
|
||||
BSP_MAX2771_ERR_CLOCK = -4,
|
||||
BSP_MAX2771_ERR_VERIFY = -5
|
||||
} bsp_max2771_status_t;
|
||||
|
||||
/* Validate the dedicated MMIO IP, its board clock, and its idle state. */
|
||||
bsp_max2771_status_t bsp_max2771_spi_init(void);
|
||||
|
||||
/* Execute one complete, hardware-timed 48-SCLK MAX2771 transaction. */
|
||||
bsp_max2771_status_t bsp_max2771_write(uint8_t address, uint32_t value);
|
||||
bsp_max2771_status_t bsp_max2771_read(uint8_t address, uint32_t *value);
|
||||
|
||||
/* Write then read one register. The readback must equal the written value. */
|
||||
bsp_max2771_status_t bsp_max2771_write_verified(uint8_t address, uint32_t value);
|
||||
|
||||
uint32_t bsp_max2771_input_clock_hz(void);
|
||||
uint32_t bsp_max2771_sclk_hz(void);
|
||||
uint32_t bsp_max2771_half_period_cycles(void);
|
||||
uint32_t bsp_max2771_status(void);
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@
|
||||
#define BSP_UART_BASE 0x10013000UL
|
||||
#define BSP_SPI_BASE 0x10014000UL
|
||||
#define BSP_PMOD_SPI_BASE 0x10015000UL
|
||||
#define BSP_MAX2771_SPI_BASE 0x10016000UL
|
||||
#define BSP_GPS_ACQ_BASE 0x10020000UL
|
||||
#define BSP_GPS_TRCK0_BASE 0x10021000UL
|
||||
#define BSP_GPS_TRCK_STRIDE 0x00001000UL
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
TARGET := max2771_spi_test
|
||||
APP_SRCS := main.c
|
||||
BSP_SRCS := init.c uart.c max2771_spi.c
|
||||
|
||||
# Direct builds default to Genesys 2. Board flows override these values.
|
||||
BSP_UART_CLOCK_HZ ?= 50000000
|
||||
BSP_CLINT_TIMEBASE_HZ ?= 500000
|
||||
BSP_MAX2771_INPUT_CLOCK_HZ ?= $(BSP_UART_CLOCK_HZ)
|
||||
|
||||
include ../common/app.mk
|
||||
|
||||
CFLAGS += -DBSP_MAX2771_INPUT_CLOCK_HZ=$(BSP_MAX2771_INPUT_CLOCK_HZ)UL
|
||||
@@ -0,0 +1,48 @@
|
||||
# MAX2771 SPI Register Test
|
||||
|
||||
This bare-metal application exercises the dedicated MAX2771 three-wire SPI IP
|
||||
at `0x10016000`. It does not use or alter the generic PMOD SPI peripheral.
|
||||
|
||||
The test uses the complete default register table from the
|
||||
[MAX2771 data sheet](https://www.analog.com/media/en/technical-documentation/data-sheets/max2771.pdf).
|
||||
It writes registers `0x0` through `0xA`, reads each register back immediately,
|
||||
then performs a second full read sweep and prints all values. Registers `0x0`
|
||||
and `0x9` therefore receive the mandatory reserved-bit values required after
|
||||
every MAX2771 power cycle.
|
||||
|
||||
Build directly:
|
||||
|
||||
```bash
|
||||
make -C soc/software max2771-spi-test
|
||||
```
|
||||
|
||||
Build through a board flow:
|
||||
|
||||
```bash
|
||||
make -C targets/fpga/genesys2 software APP=max2771_spi_test
|
||||
make -C targets/fpga/vcu118 software APP=max2771_spi_test
|
||||
```
|
||||
|
||||
For a fast RAM-loaded Genesys 2 test:
|
||||
|
||||
```bash
|
||||
make -C targets/fpga/genesys2 debug-load APP=max2771_spi_test
|
||||
make -C targets/fpga/genesys2 uart-listen
|
||||
```
|
||||
|
||||
Expected final output is:
|
||||
|
||||
```text
|
||||
PASS,MAX2771 defaults programmed and verified
|
||||
```
|
||||
|
||||
## EV Kit Connection
|
||||
|
||||
The EV kit already has a MAX32625 PICO MCU connected to `SPI_CLK`, `SPI_CSN`,
|
||||
and `SPI_DATA`. Before connecting the FPGA, disconnect that controller or put
|
||||
all three MCU pins in high impedance and do not run the EV kit GUI. Two active
|
||||
masters on `SPI_DATA` can cause electrical contention.
|
||||
|
||||
Connect `SCLK`, `CSN`, the single bidirectional `SDATA`, and a common ground.
|
||||
Power the EV kit according to its own guide. Do not connect the FPGA board's
|
||||
PMOD power pin to an independently powered EV kit.
|
||||
@@ -0,0 +1,81 @@
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "bsp/max2771_spi.h"
|
||||
#include "bsp/soc.h"
|
||||
#include "bsp/uart.h"
|
||||
|
||||
/* MAX2771 data sheet Table 2, including the mandatory reserved-bit values. */
|
||||
static const uint32_t max2771_default_registers[BSP_MAX2771_REGISTER_COUNT] = {
|
||||
0xbea41603u,
|
||||
0x20550288u,
|
||||
0x0eafa1dcu,
|
||||
0x698c0008u,
|
||||
0x00c00080u,
|
||||
0x08000070u,
|
||||
0x08000000u,
|
||||
0x010061b2u,
|
||||
0x01e0f401u,
|
||||
0x00c00002u,
|
||||
0x010061b0u
|
||||
};
|
||||
|
||||
static int report_error(const char *operation,
|
||||
unsigned int address,
|
||||
bsp_max2771_status_t status)
|
||||
{
|
||||
printf("FAIL,%s,reg=0x%x,status=%d\n", operation, address, (int)status);
|
||||
bsp_uart_wait_tx_idle();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("\nMAX2771 dedicated three-wire SPI test\n");
|
||||
printf("MMIO,0x%08lx\n", (unsigned long)BSP_MAX2771_SPI_BASE);
|
||||
|
||||
bsp_max2771_status_t status = bsp_max2771_spi_init();
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return report_error("init", 0u, status);
|
||||
}
|
||||
|
||||
printf("CLOCK,input_hz=%lu,expected_input_hz=%lu,sclk_hz=%lu,half_cycles=%lu,max_hz=%u\n",
|
||||
(unsigned long)bsp_max2771_input_clock_hz(),
|
||||
(unsigned long)BSP_MAX2771_INPUT_CLOCK_HZ,
|
||||
(unsigned long)bsp_max2771_sclk_hz(),
|
||||
(unsigned long)bsp_max2771_half_period_cycles(),
|
||||
BSP_MAX2771_MAX_SCLK_HZ);
|
||||
|
||||
for (unsigned int address = 0u;
|
||||
address < BSP_MAX2771_REGISTER_COUNT;
|
||||
++address) {
|
||||
status = bsp_max2771_write_verified(
|
||||
(uint8_t)address, max2771_default_registers[address]);
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return report_error("write_verify", address, status);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned int address = 0u;
|
||||
address < BSP_MAX2771_REGISTER_COUNT;
|
||||
++address) {
|
||||
uint32_t value = 0u;
|
||||
status = bsp_max2771_read((uint8_t)address, &value);
|
||||
if (status != BSP_MAX2771_OK) {
|
||||
return report_error("read", address, status);
|
||||
}
|
||||
printf("REGISTER,0x%x,0x%08lx\n", address, (unsigned long)value);
|
||||
if (value != max2771_default_registers[address]) {
|
||||
printf("FAIL,read_verify,reg=0x%x,expected=0x%08lx,actual=0x%08lx\n",
|
||||
address,
|
||||
(unsigned long)max2771_default_registers[address],
|
||||
(unsigned long)value);
|
||||
bsp_uart_wait_tx_idle();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("PASS,MAX2771 defaults programmed and verified\n");
|
||||
bsp_uart_wait_tx_idle();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user