cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Highlighted
Visitor
Visitor
6,364 Views
Registered: ‎07-14-2014

Read/Write AXI Quad SPI IP with Vivado HLS

Hi,

 

I'm currently exploring ways, on how to implement some flight controllers and navigation algorithms on a Zynq SoC device.

 

Some low level control laws should be implemented on the PL for robustness and all sensor messurements should be collected by the PL as well.

 

I'm trying to read inertial acceleration messurements from an ADIS16407 via SPI by implementing an AXI Master interface in Vivado HLS and connecting it to the shipped 'AXI Quad SPI' IP. I did consult the documentation of the AXI Quad SPI and AXI Master Lite interface but I still have no glue on how to proceed.

 

How do I read register XY from the SPI slave with HLS? (Some code snippets would be highly appreciated)

 

Any hints and useful links are welcome - thanks in advance!

 

Regards,

Pascal

 

0 Kudos
3 Replies
Highlighted
Visitor
Visitor
6,162 Views
Registered: ‎09-16-2014

I too need to know if I am able to read/write to the AXI Quad SPI interface from HLS. Have you had any luck in figuring this out?

0 Kudos
Highlighted
Visitor
Visitor
5,997 Views
Registered: ‎07-14-2014

Hi,

 

sorry for the delayed response. Yes I have been able to use the AXI Quad SPI IP for a few days now.

Some snippets of my c++ code without any warranty of course. Maybe this will give someone a starting point.

 

Don't forget to set the Slave's (AXI Quad SPI) Base Address in the created IP Core using Vivado.

 

void sen_imu_spi(volatile uint32_t* spi_bus, volatile int32_t* data) {
#pragma HLS INTERFACE ap_none port=data
#pragma HLS INTERFACE s_axilite port=data bundle=data
#pragma HLS INTERFACE m_axi port=spi_bus offset=off

SetRegister(busPtr, RegisterSpace::SPIDTR, 0x0); // Initial data
SetRegister(busPtr, RegisterSpace::SPISSR, 0xFFFFFFFF); // Disable Slaves
SetRegister(busPtr, RegisterSpace::SPICR, 0x18E); // Transaction Inhibit, Manual Slave Select, SPI System Enable

*data = Bus::Transfer(spi_bus, 0, 0x0A00) // Write new register Address, Read last transmitted Register (X Acceleration)

}

uint32_t Bus::Transfer(volatile uint32_t* busPtr, ap_uint<5> slave_id, uint32_t tx_value,
		TransferMode transfer_mode) {

	SetRegister(busPtr, RegisterSpace::SPIDTR, tx_value);// write data transfer register

	ClearBit(busPtr, RegisterSpace::SPISSR, slave_id);// set chip-select of slave low (enable)

	ClearBit(busPtr, RegisterSpace::SPICR, 8);	// clear master transaction inhibit bit

	// wait for tx to finish
	while (ReadBit(busPtr, RegisterSpace::SPISR, 2) != OCM::Value::High)
		// Bit 2 => Tx_Empty Bit
		;

	// wait for rx to finish
	while (ReadBit(busPtr, RegisterSpace::SPISR, 1) != OCM::Value::High)
		// Bit 1 => Rx_Full Bit
		;

	SetBit(busPtr, RegisterSpace::SPICR, 8);	// set master transaction inhibit bit

	if (transfer_mode == TransferMode::Last)
		SetBit(busPtr, RegisterSpace::SPISSR, slave_id);// set chip-select of slave high (disable)

	return ReadRegister(busPtr, RegisterSpace::SPIDRR);
}

void Bus::SetBit(volatile uint32_t* busPtr, RegisterSpace register_space, ap_uint<5> position) {
	busPtr[GetOffset(register_space)] |= (1 << position);
}

void Bus::ClearBit(volatile uint32_t* busPtr, RegisterSpace register_space, ap_uint<5> position) {
	busPtr[GetOffset(register_space)] &= ~(1 << position);
}

void Bus::SetRegister(volatile uint32_t* busPtr, RegisterSpace register_space, uint32_t value) {
	busPtr[GetOffset(register_space)] = value;
}

uint32_t Bus::ReadRegister(volatile uint32_t* busPtr, RegisterSpace register_space) {
	return busPtr[GetOffset(register_space)];
}

OCM::Value Bus::ReadBit(volatile uint32_t* busPtr, RegisterSpace register_space, ap_uint<5> position) {
	if ((ReadRegister(busPtr, register_space) & (1 << position)) == (1 << position)) {
		return OCM::Value::High;
	}
	return OCM::Value::Low;
}

uint32_t Bus::GetOffset(RegisterSpace register_space)
{
	return static_cast<uint32_t>(register_space) / sizeof(uint32_t);
}

 

0 Kudos
Highlighted
4,343 Views
Registered: ‎06-14-2016

Check this Example:

https://secure.xilinx.com/webreg/clickthrough.do?cid=359071

 

and read "xapp1204-integrating-axi4-ip-using-ip-integrator" pdf from xilinx

 

input is an AXI stream and output controls the Quad-SPI IP with axi master

but you could use the idea for your need

the hls code would be something like this:

 

//
// spi_axi_merge.c
//
// This HLS function generates AXI-4 master transactions to initialize and
// feed data to Xilinx IP core Quad SPI via its AXI-4-Lite port. See PG153
// for info on the core.
//
// The SPI port for this application is connected to AD5065 DAC on AMS //Eval.
//Board.
// After initializing the SPI core, this function reads an input AXI data
//stream, formats
// the data word for use by AD5065 on AMS Eval. Board. and sends the
//formatted
// data word to the SPI core.


#include "spi_axi_merge.h"
void spi_axi_merge (volatile DT *m, STREAM_DT data_i[N],
unsigned short decimation_factor, unsigned short *sample_count_out ) {
#pragma HLS PIPELINE II=1 enable_flush
// Define the RTL interfaces
#pragma HLS interface ap_stable port=sample_count_out
#pragma HLS interface ap_stable port=decimation_factor
#pragma HLS interface ap_ctrl_none port=return
#pragma HLS interface m_axi port=m
// AXI4-Stream slave interface
#pragma HLS interface axis port=data_i
STREAM_DT ddfs_data_bipolar;
DT ddfs_data_unipolar;
DT ddfs_data_unipolar_fmt;
static unsigned short sample_count = 1;
#pragma HLS RESET variable=sample_count
static unsigned char state = 0;
#pragma HLS RESET variable=state
switch (state)
{
case 0: // SPI Control Register setup
*(m+SPICR_OFFSET) = 0x4 | 0x8 | 0x2; // Master, CPOL, SPE
state++;
break;
case 1: // SPI Slave select Register setup (active low)
*(m+SPISSR_OFFSET) = 0xFFFE;
state++;
break;
default: // read DDFS stream and decimate to meet DAC SPI bandwidth limit
ddfs_data_bipolar = data_i[0];
// convert bipolar DDFS output to unipolar for DAC
ddfs_data_unipolar = ddfs_data_bipolar + 32768;
// shift by 4 for DAC SPI format
ddfs_data_unipolar_fmt = ddfs_data_unipolar << 4;
if (sample_count < decimation_factor) {
sample_count++;
} else {
sample_count = 1;
*(m+SPIDTR_OFFSET) = (0x03000000 | ddfs_data_unipolar_fmt); // format
input stream for DAC: write to channel A
}
break;
} // end switch
*sample_count_out = sample_count;
} // end of function
0 Kudos