Skip to content

Commit

Permalink
Added comments SDK. then got bored. Still need to resolve the dummy c…
Browse files Browse the repository at this point in the history
…ycles.
  • Loading branch information
JuanSapriza committed Jan 30, 2025
1 parent eea351b commit 2411605
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 41 deletions.
25 changes: 16 additions & 9 deletions sw/applications/example_spi_slave/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/* By default, printfs are activated for FPGA and disabled for simulation. */
#define PRINTF_IN_FPGA 1
#define PRINTF_IN_SIM 1
#define PRINTF_IN_SIM 0

#if TARGET_SIM && PRINTF_IN_SIM
#define PRINTF(fmt, ...) printf(fmt, ##__VA_ARGS__)
Expand All @@ -20,9 +20,8 @@
#define DATA_LENGTH_B 21
#define DUMMY_CYCLES 32

uint8_t source_data_B[DATA_LENGTH_B] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 };
uint8_t write_data_B[DATA_LENGTH_B];
uint8_t read_data_B[DATA_LENGTH_B];
uint8_t buffer_1[DATA_LENGTH_B] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 };
uint8_t buffer_2[DATA_LENGTH_B];

static spi_host_t* host;

Expand All @@ -31,28 +30,36 @@ int main(){
host = spi_host1;
spi_return_flags_e flags;

// Initialize the SPI host to transmit data to the SPI slave
if( spi_host_init(host)!= SPI_FLAG_SUCCESS) {
PRINTF("Failure to initialize\n\r");
return EXIT_FAILURE;
}

if( spi_slave_write(host, write_data_B, source_data_B, DATA_LENGTH_B) != SPI_FLAG_SUCCESS) {
// Use the SPI Host SDK to write into the SPI slave.
// In the SPI Slave SDK there are the needed SPI HOST functions to control the SPI Slave.
// The SPI slave per se cannot be controlled from X-HEEP's SW.
if( spi_slave_write(host, buffer_2, buffer_1, DATA_LENGTH_B) != SPI_FLAG_SUCCESS) {
PRINTF("Failure to write\n\r");
return EXIT_FAILURE;
}

// Check that the written values match the source ones.
// Also increment those values +1 to use as new data.
for(int i=0; i < DATA_LENGTH_B; i++){
if(source_data_B[i] != write_data_B[i]) return EXIT_FAILURE;
write_data_B[i] = i+1;
if(buffer_1[i] != buffer_2[i]) return EXIT_FAILURE;
buffer_2[i] = i+1;
}

if( spi_slave_read(host, write_data_B, read_data_B, DATA_LENGTH_B, DUMMY_CYCLES) != SPI_FLAG_SUCCESS) {
// Use the SPI Host SDK to read from the SPI slave and store the read values in buffer 1
if( spi_slave_read(host, buffer_2, buffer_1, DATA_LENGTH_B, DUMMY_CYCLES*2) != SPI_FLAG_SUCCESS) {
PRINTF("Failure to read\n\r");
return EXIT_FAILURE;
}

// check that the new values still match
for(int i=0; i < DATA_LENGTH_B; i++){
if(source_data_B[i] != write_data_B[i]) return EXIT_FAILURE;
if(buffer_1[i] != buffer_2[i]) return EXIT_FAILURE;
}

return EXIT_SUCCESS;
Expand Down
69 changes: 48 additions & 21 deletions sw/device/lib/sdk/spi_slave/spi_slave_sdk.c
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
#include "spi_slave_sdk.h"
// Copyright 2025 EPFL
// Solderpad Hardware License, Version 2.1, see LICENSE.md for details.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// File: spi_slave_sdk.c
// Author: Juan Sapriza
// Description: This is not an actual SDK. The SPI slave cannot be controlled from
// software. This "misleading file" is using the SPI Host SDK to read and write
// to the SPI slave.


#include "spi_slave_sdk.h"


/*
* Initilize the SPI Host
*/
spi_flags_e spi_host_init(spi_host_t* host) {

// Enable spi host device
if( spi_set_enable(host, true) != SPI_FLAG_SUCCESS) return SPI_HOST_FLAG_NOT_INIT;
if(spi_output_enable(host, true) != SPI_FLAG_SUCCESS) return SPI_HOST_FLAG_NOT_INIT;
if( spi_output_enable(host, true) != SPI_FLAG_SUCCESS) return SPI_HOST_FLAG_NOT_INIT;

// Spi Configuration
// Configure chip 0 (slave)
Expand All @@ -26,47 +39,61 @@ spi_flags_e spi_host_init(spi_host_t* host) {
return SPI_FLAG_SUCCESS; // Success
}

/**
* @brief Command the SPI slave to write in memory
*
* @param host The SPI host instance
* @param addr uint8_t pointer to memory where the data will be written.
* @param data uint8_t pointer to memory where the data to be written will be copied from.
* @param length_B Length (in bytes) of the data to be copied.
* @return SPI_FLAG_SUCCESS always
*/
spi_flags_e spi_slave_write(spi_host_t* host, uint8_t* addr, uint8_t* data, uint16_t length_B) {

uint32_t length_W = length_B >> 2;
uint8_t remaining_bytes = length_B % 4;
uint32_t length_W_tx = remaining_bytes ? length_W +1 : length_W;
uint32_t length_W = length_B >> 2; // The length in bytes is converted to length in 32-bit words
uint8_t remaining_bytes = length_B % 4; // The bytes that do not fit in full words are managed separately
uint32_t length_W_tx = remaining_bytes ? length_W +1 : length_W; // We will request the SPI to write an extra word if there are remaining bytes

uint32_t wrap_length_W_cmds = (WRITE_SPI_SLAVE_REG_1) // Move to the lowest byte
// Write the wrap length: How many words will be sent
uint32_t wrap_length_W_cmds = (WRITE_SPI_SLAVE_REG_1) // Move to the lowest byte
| ((length_W_tx & 0xFF) << 8) // Convert Length in bytes to length in words and move to the second lowest byte
| (WRITE_SPI_SLAVE_REG_2 << 16) // Move to the second highest byte
| (((length_W_tx >> 8) & 0xFF) << 24); // Convert Length in bytes to length in words and move to the highest byte
| (WRITE_SPI_SLAVE_REG_2 << 16) // Move to the second highest byte
| (((length_W_tx >> 8) & 0xFF) << 24); // Convert Length in bytes to length in words and move to the highest byte

spi_write_word(host, wrap_length_W_cmds);
spi_wait_for_ready(host);
send_command_to_spi_host(host, 4, true, SPI_DIR_TX_ONLY);
// Send the wrap length (how many words are going to be sent)
spi_write_word(host, wrap_length_W_cmds); // The value is added to the buffer
spi_wait_for_ready(host); // Blockingly wait until the SPI host is free
send_command_to_spi_host(host, 4, true, SPI_DIR_TX_ONLY); // Send the command. One full word.

spi_write_byte(host, WRITE_SPI_SLAVE_CMD);
spi_wait_for_ready(host);
send_command_to_spi_host(host, 1, true, SPI_DIR_TX_ONLY);
// Send the command to instruct the slave that it will be writing in memory
spi_write_byte(host, WRITE_SPI_SLAVE_CMD); // The value is added to the buffer
spi_wait_for_ready(host); // Blockingly wait until the SPI host is free
send_command_to_spi_host(host, 1, true, SPI_DIR_TX_ONLY); // Send the command. One full word.

///write address
spi_write_word(host, REVERT_ENDIANNESS((uint32_t)addr));
spi_wait_for_ready(host);
send_command_to_spi_host(host, 4, true, SPI_DIR_TX_ONLY);
///write the address in memory where the data needs to be written to
spi_write_word(host, REVERT_ENDIANNESS((uint32_t)addr)); // The value is added to the buffer
spi_wait_for_ready(host); // Blockingly wait until the SPI host is free
send_command_to_spi_host(host, 4, true, SPI_DIR_TX_ONLY); // Send the command. One full word.


/*
* Place data in TX FIFO
* We fill the FIFO of the SPI host and then flush every 72 words (the depth of the fifo)
* We fill the FIFO of the SPI host and then flush every 72 words (the depth of the fifo).
*/
uint16_t words_in_fifo = 0;
uint32_t *data_32bit = (uint32_t *)data;
for (uint16_t i = 0; i < length_W; i++) {
if( words_in_fifo == SPI_HOST_PARAM_TX_DEPTH){
send_command_to_spi_host(host, SPI_HOST_PARAM_TX_DEPTH*4, true, SPI_DIR_TX_ONLY);
words_in_fifo = 0;
}
spi_wait_for_tx_not_full(host);
spi_write_word(host, REVERT_ENDIANNESS(data_32bit[i]));
spi_write_word(host, REVERT_ENDIANNESS( ((uint32_t *)data)[i]));
words_in_fifo++;
}

/*
* The remaining bytes are added to an extra word. The copied word from memory is cleaned with a mask before sending.
*/
if ( remaining_bytes ) {
uint32_t mask = (1 << (8 * remaining_bytes)) - 1; // Only keep the remaining bytes with a mask
uint32_t last_word = ((uint32_t*)data)[length_W] & mask;
Expand Down
26 changes: 15 additions & 11 deletions sw/device/lib/sdk/spi_slave/spi_slave_sdk.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// Copyright 2025 EPFL
// Solderpad Hardware License, Version 2.1, see LICENSE.md for details.
// SPDX-License-Identifier: Apache-2.0 WITH SHL-2.1
//
// File: spi_slave_sdk.h
// Author: Juan Sapriza
// Description: This is not an actual SDK. The SPI slave cannot be controlled from
// software. This "misleading file" is using the SPI Host SDK to read and write
// to the SPI slave.


#include "spi_host.h"

Expand All @@ -10,11 +20,11 @@


/** Macros for SPI SLAVE hardware. */
#define WRITE_SPI_SLAVE_REG_0 0x11
#define WRITE_SPI_SLAVE_REG_1 0x20
#define WRITE_SPI_SLAVE_REG_2 0x30
#define READ_SPI_SLAVE_CMD 0xB
#define WRITE_SPI_SLAVE_CMD 0x2
#define WRITE_SPI_SLAVE_REG_0 0x11 // Used to specify the amount of dummy cycles
#define WRITE_SPI_SLAVE_REG_1 0x20 // To store the 8 LSBs of the wrap length
#define WRITE_SPI_SLAVE_REG_2 0x30 // To store the 8 MSBs of the wrap length
#define READ_SPI_SLAVE_CMD 0xB // Command the SPI slave to READ from memory and send data out
#define WRITE_SPI_SLAVE_CMD 0x2 // Command the SPI slave to receive data and WRITE it to memory


/** Enum for SPI operation status flags. */
Expand All @@ -31,12 +41,6 @@ typedef enum {
SPI_SLAVE_FLAG_SIZE_OF_DATA_EXCEEDED = 0x0004,
} spi_flags_e;

typedef enum {
OPERATION_WRITE,
OPERATION_READ
} OperationType;


spi_flags_e spi_host_init(spi_host_t* host);
spi_flags_e spi_slave_write(spi_host_t* host, uint8_t* addr, uint8_t* data, uint16_t length_B);
spi_flags_e spi_slave_read(spi_host_t* host, uint8_t* addr, uint8_t* data, uint16_t length, uint8_t dummy_cycles);
Expand Down

0 comments on commit 2411605

Please sign in to comment.