[loggers] Direct memory logger

This commit is contained in:
Freek van Tienen
2014-09-04 01:10:54 +02:00
parent 42192213e5
commit 9e3510e51e
9 changed files with 755 additions and 28 deletions
@@ -45,6 +45,7 @@
<modules> <modules>
<load name="gps_ubx_ucenter.xml"/> <load name="gps_ubx_ucenter.xml"/>
<!-- load name="airspeed_ms45xx.xml"/ --> <!-- load name="airspeed_ms45xx.xml"/ -->
<load name="direct_memory_logger.xml"/>
</modules> </modules>
<servos driver="Asctec_v2"> <servos driver="Asctec_v2">
+1 -1
View File
@@ -136,7 +136,7 @@
radio="radios/cockpitSX.xml" radio="radios/cockpitSX.xml"
telemetry="telemetry/default_rotorcraft.xml" telemetry="telemetry/default_rotorcraft.xml"
flight_plan="flight_plans/rotorcraft_basic.xml" flight_plan="flight_plans/rotorcraft_basic.xml"
settings=" settings/rotorcraft_basic.xml settings/control/rotorcraft_guidance.xml settings/control/stabilization_att_int.xml settings/control/stabilization_rate.xml settings/estimation/ahrs_int_cmpl_quat.xml" settings=" settings/rotorcraft_basic.xml settings/control/rotorcraft_guidance.xml settings/control/stabilization_att_int.xml settings/control/stabilization_rate.xml settings/estimation/ahrs_int_cmpl_quat.xml settings/modules/direct_memory_logger.xml"
gui_color="#710080" gui_color="#710080"
/> />
<aircraft <aircraft
+49
View File
@@ -0,0 +1,49 @@
<!DOCTYPE module SYSTEM "module.dtd">
<module name="loggers">
<doc>
<description>
Directly log values to memory for flash chips.
</description>
<configure name="DM_LOG_UART" value="UART1|UART2|UART3|UART4|UART5|UART6" description="Port to read back the memory"/>
<configure name="DM_LOG_SPI_DEV" value="SPI1|SPI2|SPI3|SPI4|SPI5|SPI6" description="SPI bus which the memory is connected to"/>
<configure name="DM_LOG_SPI_SLAVE" value="SPI_SLAVE1|SPI_SLAVE2|SPI_SLAVE3|SPI_SLAVE4|SPI_SLAVE5|SPI_SLAVE6" description="SPI slave which the memory is connected to"/>
</doc>
<header>
<file name="direct_memory_logger.h"/>
</header>
<init fun="direct_memory_logger_init()"/>
<periodic fun="direct_memory_logger_periodic()" autorun="TRUE"/>
<makefile target="ap">
<raw>
DM_LOG_UART ?= uart1
DM_LOG_UART_LOWER=$(shell echo $(DM_LOG_UART) | tr A-Z a-z)
DM_LOG_UART_UPPER=$(shell echo $(DM_LOG_UART) | tr a-z A-Z)
DM_LOG_SPI_DEV ?= spi2
DM_LOG_SPI_DEV_LOWER=$(shell echo $(DM_LOG_SPI_DEV) | tr A-Z a-z)
DM_LOG_SPI_DEV_UPPER=$(shell echo $(DM_LOG_SPI_DEV) | tr a-z A-Z)
DM_LOG_SPI_SLAVE_IDX ?= spi_slave1
DM_LOG_SPI_SLAVE_IDX_LOWER=$(shell echo $(DM_LOG_SPI_SLAVE_IDX) | tr A-Z a-z)
DM_LOG_SPI_SLAVE_IDX_UPPER=$(shell echo $(DM_LOG_SPI_SLAVE_IDX) | tr a-z A-Z)
include $(CFG_SHARED)/spi_master.makefile
</raw>
<define name="USE_$(DM_LOG_SPI_DEV_UPPER)" value="1" />
<define name="USE_$(DM_LOG_SPI_SLAVE_IDX_UPPER)" value="1" />
<define name="DM_LOG_SPI_DEV" value="$(DM_LOG_SPI_DEV_LOWER)" />
<define name="DM_LOG_SPI_SLAVE_IDX" value="$(DM_LOG_SPI_SLAVE_IDX_UPPER)" />
<define name="DM_LOG_UART" value="$(DM_LOG_UART_UPPER)"/>
<define name="USE_$(DM_LOG_UART_UPPER)"/>
<define name="$(DM_LOG_UART_UPPER)_BAUD" value="B230400"/>
<file name="direct_memory_logger.c"/>
<file name="sst25vfxxxx.c" dir="peripherals"/>
</makefile>
</module>
@@ -0,0 +1,13 @@
<!DOCTYPE settings SYSTEM "../settings.dtd">
<settings>
<dl_settings name="direct_memory_logger">
<dl_settings name="direct_memory">
<dl_setting module="loggers/direct_memory_logger" var="dml.status" shortname="Status" min="0" step="1" max="2" values="INIT|IDLE|ERASE|START|RUNNING|STOP|READ|READING" handler="set"/>
<dl_setting module="loggers/direct_memory_logger" var="dml.sst.flash_addr" shortname="Flash ADDR" min="0" step="1" max="16777215"/>
<dl_setting module="loggers/direct_memory_logger" var="dml.write_addr" shortname="Write ADDR" min="0" step="1" max="16777215"/>
</dl_settings>
</dl_settings>
</settings>
+7 -27
View File
@@ -124,39 +124,19 @@
#define PPM_GPIO_AF GPIO_AF8 #define PPM_GPIO_AF GPIO_AF8
/* SPI */ /* SPI */
#define SPI1_GPIO_AF GPIO_AF5
#define SPI1_GPIO_PORT_MISO GPIOA
#define SPI1_GPIO_MISO GPIO6
#define SPI1_GPIO_PORT_MOSI GPIOA
#define SPI1_GPIO_MOSI GPIO7
#define SPI1_GPIO_PORT_SCK GPIOA
#define SPI1_GPIO_SCK GPIO5
#define SPI2_GPIO_AF GPIO_AF5 #define SPI2_GPIO_AF GPIO_AF5
#define SPI2_GPIO_PORT_MISO GPIOB #define SPI2_GPIO_PORT_MISO GPIOC
#define SPI2_GPIO_MISO GPIO14 #define SPI2_GPIO_MISO GPIO2
#define SPI2_GPIO_PORT_MOSI GPIOB #define SPI2_GPIO_PORT_MOSI GPIOC
#define SPI2_GPIO_MOSI GPIO15 #define SPI2_GPIO_MOSI GPIO3
#define SPI2_GPIO_PORT_SCK GPIOB #define SPI2_GPIO_PORT_SCK GPIOB
#define SPI2_GPIO_SCK GPIO13 #define SPI2_GPIO_SCK GPIO10
#define SPI_SELECT_SLAVE0_PORT GPIOA #define SPI_SELECT_SLAVE0_PORT GPIOA
#define SPI_SELECT_SLAVE0_PIN GPIO15 #define SPI_SELECT_SLAVE0_PIN GPIO0
#define SPI_SELECT_SLAVE1_PORT GPIOA #define SPI_SELECT_SLAVE1_PORT GPIOA
#define SPI_SELECT_SLAVE1_PIN GPIO4 #define SPI_SELECT_SLAVE1_PIN GPIO5
#define SPI_SELECT_SLAVE2_PORT GPIOB
#define SPI_SELECT_SLAVE2_PIN GPIO12
#define SPI_SELECT_SLAVE3_PORT GPIOC
#define SPI_SELECT_SLAVE3_PIN GPIO13
#define SPI_SELECT_SLAVE4_PORT GPIOC
#define SPI_SELECT_SLAVE4_PIN GPIO12
#define SPI_SELECT_SLAVE5_PORT GPIOC
#define SPI_SELECT_SLAVE5_PIN GPIO4
/* I2C mapping */ /* I2C mapping */
@@ -0,0 +1,221 @@
/*
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
/**
* @file modules/loggers/direct_memory_logger.c
* @brief Write logs directly to flash memory chips
*/
#include "direct_memory_logger.h"
#include "mcu_periph/uart.h"
#include "subsystems/imu.h"
#include "stabilization.h"
struct DirectMemoryLogger dml;
static void direct_memory_spi_cb(struct spi_transaction* trans);
static int32_t seq_in_array(uint8_t* array, uint16_t array_size, uint8_t* sequence, uint16_t sequence_size);
// Different sequences
static uint8_t start_log_sequence[6] = {0xAA, 0x55, 0xFF, 0x00, 0x55, 0xAA};
static uint8_t stop_log_sequence[6] = {0xFF, 0x00, 0x55, 0xAA, 0x10, 0xFF};
// The logging output connection
#define __DMLoggerLink(dev, _x) dev##_x
#define _DMLoggerLink(dev, _x) __DMLoggerLink(dev, _x)
#define DMLoggerLink(_x) _DMLoggerLink(DM_LOG_UART, _x)
// Logging struct
struct LogStruct {
uint32_t counter;
int32_t accel_z;
int32_t gyro_p;
int32_t gyro_q;
int32_t gyro_r;
int32_t thrust;
} __attribute__((packed));
static struct LogStruct log_struct;
static uint32_t dm_counter = 0;
static int32_t seq_in_array(uint8_t* array, uint16_t array_size, uint8_t* sequence, uint16_t sequence_size)
{
uint16_t i;
static uint16_t current_sequence_id = 0;
static uint16_t count_ff = 0;
for (i = 0; i < array_size; i++) {
// Detect stop sequence
if (array[i] == sequence[current_sequence_id]) {
current_sequence_id++;
if (current_sequence_id >= sequence_size) {
count_ff = 0;
current_sequence_id = 0;
return i;
}
} else {
current_sequence_id = 0;
}
// Detect ff sequence
if (array[i] == 0xFF) {
count_ff++;
if (count_ff >= 1000) {
count_ff = 0;
current_sequence_id = 0;
return i;
}
} else {
count_ff = 0;
}
}
return -1;
}
void direct_memory_logger_init(void)
{
dml.status = DML_INIT;
// Initialize the sst chip
sst25vfxxxx_init(&dml.sst, &(DM_LOG_SPI_DEV), DM_LOG_SPI_SLAVE_IDX, &direct_memory_spi_cb);
}
void direct_memory_logger_periodic(void)
{
int32_t seq_idx;
uint16_t i, end_idx;
// Switch the different statusses
switch (dml.status) {
case DML_IDLE:
// Do nothing
break;
// Stopping
case DML_STOP:
if (dml.sst.status != SST25VFXXXX_IDLE) {
break;
}
dml.status = DML_IDLE;
dml.write_addr = dml.sst.flash_addr + 6;
sst25vfxxxx_write(&dml.sst, stop_log_sequence, 6);
break;
// Logging
case DML_START:
dm_counter = 0;
dml.status = DML_LOGGING;
case DML_LOGGING:
// Check if too slow TODO fix error
dm_counter++;
if (dml.sst.status != SST25VFXXXX_IDLE) {
break;
}
// Set the log values
log_struct.counter++;
log_struct.accel_z = imu.accel.z;
log_struct.gyro_p = imu.gyro.p;
log_struct.gyro_q = imu.gyro.q;
log_struct.gyro_r = imu.gyro.r;
log_struct.thrust = stabilization_cmd[COMMAND_THRUST];
sst25vfxxxx_write(&dml.sst, (uint8_t*) &log_struct, sizeof(struct LogStruct));
break;
// Reading
case DML_READ:
dml.status = DML_READING;
case DML_READING:
if (DMLoggerLink(TxRunning) || dml.sst.status != SST25VFXXXX_IDLE) {
break;
}
// Detect end sequence
seq_idx = seq_in_array(&(dml.buffer[5]), DML_BUF_SIZE - 5, stop_log_sequence, 6);
if (seq_idx < 0) {
end_idx = DML_BUF_SIZE;
} else {
end_idx = seq_idx + 5;
dml.status = DML_IDLE;
}
for (i = 5; i < end_idx; i++) {
DMLoggerLink(Transmit(dml.buffer[i]));
}
// Read next bytes
dml.sst.flash_addr += end_idx - 5;
if (seq_idx < 0) {
sst25vfxxxx_read(&dml.sst, dml.buffer, DML_BUF_SIZE - 5);
}
break;
default:
if (dml.sst.status == SST25VFXXXX_IDLE) {
dml.status = DML_IDLE;
}
break;
}
}
void direct_memory_logger_set(uint8_t val)
{
// First handle stopping while logging
if (dml.status == DML_LOGGING && val == DML_STOP) {
dml.status = DML_STOP;
return;
}
// Handle only while idle
if (dml.status != DML_IDLE) {
return;
}
// Handle all the statuses
dml.status = val;
switch (dml.status) {
case DML_ERASE:
dml.sst.flash_addr = 0x0;
dml.write_addr = 0x0;
sst25vfxxxx_chip_erase(&dml.sst);
break;
case DML_START:
dml.sst.flash_addr = dml.write_addr;
sst25vfxxxx_write(&dml.sst, start_log_sequence, 6);
break;
case DML_READ:
dml.sst.flash_addr = 0x0;
sst25vfxxxx_read(&dml.sst, dml.buffer, DML_BUF_SIZE - 5);
break;
default:
break;
}
}
static void direct_memory_spi_cb(__attribute__((unused)) struct spi_transaction* trans)
{
sst25vfxxxx_after_cb(&dml.sst);
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
*/
/**
* @file modules/loggers/direct_memory_logger.h
* @brief Write logs directly to flash memory chips
*/
#ifndef DIRECT_MEMORY_LOGGER_H_
#define DIRECT_MEMORY_LOGGER_H_
#include "peripherals/sst25vfxxxx.h"
#define DML_BUF_SIZE 128 /**< The read buffer size */
/* The different statusses the Direct Memory Logger is able to be in */
enum DMLStatus {
DML_INIT, /**< The DML is initializing */
DML_IDLE, /**< The DML is idle */
DML_ERASE, /**< The DML is busy erasing itself */
DML_START, /**< The DML is starting the logger */
DML_LOGGING, /**< The DML is busy logging */
DML_STOP, /**< The DML is busy stopping */
DML_READ, /**< The DML is busy starting read */
DML_READING, /**< The DML is busy reading */
};
/* Contains all the direct memory information */
struct DirectMemoryLogger {
struct SST25VFxxxx sst; /**< The memory chip */
volatile enum DMLStatus status; /**< The status of the Direct Memory Logger */
uint8_t buffer[DML_BUF_SIZE]; /**< The buffer for writing and reading */
uint32_t write_addr;
};
extern struct DirectMemoryLogger dml;
void direct_memory_logger_init(void);
void direct_memory_logger_periodic(void);
void direct_memory_logger_set(uint8_t val);
#endif /* DIRECT_MEMORY_LOGGER_H_ */
+318
View File
@@ -0,0 +1,318 @@
/*
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* @file peripherals/sst25vfxxxx.c
* Driver for the SST25Vxxxx flash chips
*/
#include "sst25vfxxxx.h"
/* Static function defines */
/**
* Initializing the sst25vfxxxx chip
*/
void sst25vfxxxx_init(struct SST25VFxxxx* sst, struct spi_periph* spi_p, const uint8_t slave_idx, SPICallback spi_cb)
{
/* Set spi_peripheral and start flash address */
sst->spi_p = spi_p;
sst->flash_addr = 0x0;
/* Set the spi transaction */
sst->spi_t.cpol = SPICpolIdleLow;
sst->spi_t.cpha = SPICphaEdge1;
sst->spi_t.dss = SPIDss8bit;
sst->spi_t.bitorder = SPIMSBFirst;
sst->spi_t.cdiv = SPIDiv32;
sst->spi_t.input_length = 0;
sst->spi_t.output_length = 0;
sst->spi_t.input_buf = sst->input_buf;
sst->spi_t.output_buf = sst->output_buf;
sst->spi_t.slave_idx = slave_idx;
sst->spi_t.select = SPISelectUnselect;
sst->spi_t.status = SPITransDone;
sst->spi_t.after_cb = spi_cb;
/* Update the status and start with enabling writing */
sst->status = SST25VFXXXX_IDLE;
sst25vfxxxx_block_write_en(sst);
}
/**
* Callback of the SPI after going one level higher for gathering the sst pointer
*/
void sst25vfxxxx_after_cb(struct SST25VFxxxx* sst)
{
switch (sst->status) {
// Enabling writing to blocks
case SST25VFXXXX_WRITE_EN:
// When last transmit is done
if (sst->status_idx >= 1) {
sst->status = SST25VFXXXX_IDLE;
break;
}
// Write to the status register
sst->status_idx = 1;
sst->output_buf[0] = SST25VFXXXX_WRSR;
sst->output_buf[1] = 0x0;
sst->spi_t.output_length = 2;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
break;
// Erase the full chip
case SST25VFXXXX_CHIP_ERASE:
switch (sst->status_idx) {
// Execute full erase command
case 0:
sst->status_idx = 1;
sst->output_buf[0] = SST25VFXXXX_ERASE_CHIP;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
break;
// Wait for chip to finish
case 1:
// Disable writing when finished erasing
if (sst->spi_t.input_length == 2 && !(sst->input_buf[1] & 0x1)) {
sst->status_idx = 2;
sst->output_buf[0] = SST25VFXXXX_WRDI;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
break;
}
sst->status_idx = 1;
sst->output_buf[0] = SST25VFXXXX_RDSR;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 2;
spi_submit(sst->spi_p, &sst->spi_t);
break;
// Goto idle
default:
sst->status = SST25VFXXXX_IDLE;
break;
}
break;
// Write bytes to flash
case SST25VFXXXX_WRITE_BYTES:
switch (sst->status_idx) {
// Send the address with 2 or 1 byte(s) of data
case 0:
sst->status_idx = 1;
if ((sst->transfer_length - sst->transfer_idx) > 1) {
sst->output_buf[0] = SST25VFXXXX_AAI_PROG;
} else {
sst->output_buf[0] = SST25VFXXXX_BYTE_PROG;
}
sst->output_buf[1] = (sst->flash_addr >> 16) & 0xFF;
sst->output_buf[2] = (sst->flash_addr >> 8) & 0xFF;
sst->output_buf[3] = sst->flash_addr & 0xFF;
sst->output_buf[4] = sst->transfer_buf[sst->transfer_idx++];
if ((sst->transfer_length - sst->transfer_idx) > 1) {
sst->output_buf[5] = sst->transfer_buf[sst->transfer_idx++];
sst->spi_t.output_length = 6;
} else {
sst->spi_t.output_length = 5;
}
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
break;
// Read the status register
case 1:
sst->status_idx = 2;
sst->output_buf[0] = SST25VFXXXX_RDSR;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 2;
spi_submit(sst->spi_p, &sst->spi_t);
break;
// Check the status register and send new bytes if possible
case 2:
// Still busy
if (sst->input_buf[1] & 0x1) {
sst->output_buf[0] = SST25VFXXXX_RDSR;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 2;
spi_submit(sst->spi_p, &sst->spi_t);
break;
}
// Write disabeling
if ((sst->transfer_length - sst->transfer_idx) <= 0) {
sst->status_idx = 3;
sst->output_buf[0] = SST25VFXXXX_WRDI;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
break;
}
// Transfer new bytes
sst->status_idx = 1;
sst->output_buf[0] = SST25VFXXXX_AAI_PROG;
sst->output_buf[1] = sst->transfer_buf[sst->transfer_idx++];
if ((sst->transfer_length - sst->transfer_idx) <= 0) {
sst->output_buf[2] = sst->transfer_buf[sst->transfer_idx++]; //FIXME: uneven packets!!!!!
} else {
sst->output_buf[2] = 0x0;
}
sst->spi_t.output_length = 3;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
break;
// Goto idle and update the flash address
default:
sst->flash_addr += sst->transfer_length;
sst->status = SST25VFXXXX_IDLE;
break;
}
break;
// Read bytes from flash memory
case SST25VFXXXX_READ_BYTES:
// Reset the buffer pointer and goto idle
sst->spi_t.input_buf = sst->input_buf;
sst->status = SST25VFXXXX_IDLE;
break;
// Default goto idle
default:
sst->status = SST25VFXXXX_IDLE;
break;
}
}
/**
* Read the chip identifier
*/
void sst25vfxxxx_read_id(struct SST25VFxxxx* sst)
{
if (sst->status != SST25VFXXXX_IDLE) {
return;
}
// Write the read id command to the chip
sst->status = SST25VFXXXX_READ_ID;
sst->output_buf[0] = SST25VFXXXX_RDID;
sst->output_buf[1] = 0x0;
sst->output_buf[2] = 0x0;
sst->output_buf[3] = 0x0; //READ the MFG ID first
sst->spi_t.output_length = 4;
sst->spi_t.input_length = 8;
spi_submit(sst->spi_p, &sst->spi_t);
}
/**
* Enable block writing
*/
void sst25vfxxxx_block_write_en(struct SST25VFxxxx* sst)
{
if (sst->status != SST25VFXXXX_IDLE) {
return;
}
// Enable writing to the status register
sst->status = SST25VFXXXX_WRITE_EN;
sst->status_idx = 0;
sst->output_buf[0] = SST25VFXXXX_EWSR;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
}
/**
* Full chip erase
*/
void sst25vfxxxx_chip_erase(struct SST25VFxxxx* sst)
{
if (sst->status != SST25VFXXXX_IDLE) {
return;
}
// Enable writing
sst->status = SST25VFXXXX_CHIP_ERASE;
sst->status_idx = 0;
sst->output_buf[0] = SST25VFXXXX_WREN;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
}
/**
* Write bytes
*/
void sst25vfxxxx_write(struct SST25VFxxxx* sst, uint8_t* transfer_buffer, uint8_t transfer_length)
{
if (sst->status != SST25VFXXXX_IDLE) {
return;
}
// Set the transfer buffer
sst->transfer_buf = transfer_buffer; // Not copied so keep buffer available!
sst->transfer_idx = 0;
sst->transfer_length = transfer_length;
// Enable writing
sst->status = SST25VFXXXX_WRITE_BYTES;
sst->status_idx = 0;
sst->output_buf[0] = SST25VFXXXX_WREN;
sst->spi_t.output_length = 1;
sst->spi_t.input_length = 0;
spi_submit(sst->spi_p, &sst->spi_t);
}
/**
* Read bytes
* Need 5 more extra bytes because of SPI overhead
*/
void sst25vfxxxx_read(struct SST25VFxxxx* sst, uint8_t* transfer_buffer, uint8_t transfer_length)
{
if (sst->status != SST25VFXXXX_IDLE) {
return;
}
// Read all bytes at once
sst->status = SST25VFXXXX_READ_BYTES;
sst->status_idx = 0;
sst->output_buf[0] = SST25VFXXXX_HGIH_SPEAD_READ;
sst->output_buf[1] = (sst->flash_addr >> 16) & 0xFF;
sst->output_buf[2] = (sst->flash_addr >> 8) & 0xFF;
sst->output_buf[3] = sst->flash_addr & 0xFF;
sst->output_buf[4] = 0x0;
sst->spi_t.output_length = 5;
sst->spi_t.input_buf = transfer_buffer; // Need to reset this afterwards
sst->spi_t.input_length = transfer_length + 5;
spi_submit(sst->spi_p, &sst->spi_t);
}
+85
View File
@@ -0,0 +1,85 @@
/*
* Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
*
* This file is part of paparazzi.
*
* paparazzi is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* paparazzi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with paparazzi; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/**
* @file peripherals/sst25vfxxxx.h
* Driver for the SST25Vxxxx flash chips
*/
#ifndef SST25VFXXXX_H
#define SST25VFXXXX_H
#include "mcu_periph/spi.h"
/* Register defines */
#define SST25VFXXXX_READ 0x03
#define SST25VFXXXX_HGIH_SPEAD_READ 0x0B
#define SST25VFXXXX_ERASE_4K 0x20
#define SST25VFXXXX_ERASE_32K 0x52
#define SST25VFXXXX_ERASE_64K 0xD8
#define SST25VFXXXX_ERASE_CHIP 0x60
#define SST25VFXXXX_BYTE_PROG 0x02
#define SST25VFXXXX_AAI_PROG 0xAD
#define SST25VFXXXX_RDSR 0x05
#define SST25VFXXXX_EWSR 0x50
#define SST25VFXXXX_WRSR 0x01
#define SST25VFXXXX_WREN 0x06
#define SST25VFXXXX_WRDI 0x04
#define SST25VFXXXX_RDID 0x90
#define SST25VFXXXX_JEDEC_ID 0x9F
#define SST25VFXXXX_EBSY 0x70
#define SST25VFXXXX_DBSY 0x80
/* The different statuses the SST25VFxxxx chip can be in */
enum SST25VFxxxxStatus {
SST25VFXXXX_UNINIT, /**< The chip isn't initialized */
SST25VFXXXX_IDLE, /**< The chip is idle and can be used */
SST25VFXXXX_READ_ID, /**< The chip is busy with getting the chip ID */
SST25VFXXXX_WRITE_EN, /**< The chip is busy enabeling writing to blocks */
SST25VFXXXX_CHIP_ERASE, /**< The chip is busy erasing itself */
SST25VFXXXX_WRITE_BYTES, /**< The chip is busy writing bytes */
SST25VFXXXX_READ_BYTES, /**< The chip is busy reading bytes */
};
/* The structure for the SST25VFxxxx chip that handles all the buffers and requests */
struct SST25VFxxxx {
volatile enum SST25VFxxxxStatus status; /**< The status of the SST25VFxxxx flash chip */
uint8_t status_idx; /**< The counter of substatuses */
struct spi_periph* spi_p; /**< The SPI peripheral for the connection */
struct spi_transaction spi_t; /**< The SPI transaction used for the writing and reading of registers */
uint8_t input_buf[16]; /**< The input buffer for the SPI transaction */
uint8_t output_buf[16]; /**< The output buffer for the SPI transaction */
uint32_t flash_addr; /**< The flash address to write at */
uint8_t* transfer_buf; /**< The transfer buffer */
uint8_t transfer_idx; /**< The transfer idx is used for counting input/output bytes */
uint8_t transfer_length; /**< The transfer buffer length */
};
void sst25vfxxxx_init(struct SST25VFxxxx* sst, struct spi_periph* spi_p, const uint8_t slave_idx, SPICallback spi_cb);
void sst25vfxxxx_after_cb(struct SST25VFxxxx* sst);
void sst25vfxxxx_read_id(struct SST25VFxxxx* sst);
void sst25vfxxxx_block_write_en(struct SST25VFxxxx* sst);
void sst25vfxxxx_chip_erase(struct SST25VFxxxx* sst);
void sst25vfxxxx_write(struct SST25VFxxxx* sst, uint8_t* transfer_buffer, uint8_t transfer_length);
void sst25vfxxxx_read(struct SST25VFxxxx* sst, uint8_t* transfer_buffer, uint8_t transfer_length);
#endif /* SST25VFXXXX_H */