mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-06-01 21:07:40 +08:00
[loggers] Direct memory logger
This commit is contained in:
@@ -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">
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -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_ */
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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 */
|
||||||
Reference in New Issue
Block a user