forked from Archive/PX4-Autopilot
More test work on the px4io side of the serial interface.
This commit is contained in:
parent
52096f017f
commit
43210413a9
|
@ -183,6 +183,10 @@
|
|||
/* PWM failsafe values - zero disables the output */
|
||||
#define PX4IO_PAGE_FAILSAFE_PWM 105 /* 0..CONFIG_ACTUATOR_COUNT-1 */
|
||||
|
||||
/* Debug and test page - not used in normal operation */
|
||||
#define PX4IO_PAGE_TEST 127
|
||||
#define PX4IO_P_TEST_LED 0 /* set the amber LED on/off */
|
||||
|
||||
/**
|
||||
* As-needed mixer data upload.
|
||||
*
|
||||
|
|
|
@ -172,7 +172,7 @@ extern void interface_tick(void);
|
|||
/**
|
||||
* Register space
|
||||
*/
|
||||
extern void registers_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values);
|
||||
extern int registers_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values);
|
||||
extern int registers_get(uint8_t page, uint8_t offset, uint16_t **values, unsigned *num_values);
|
||||
|
||||
/**
|
||||
|
|
|
@ -185,7 +185,7 @@ uint16_t r_page_rc_input_config[MAX_CONTROL_CHANNELS * PX4IO_P_RC_CONFIG_STRIDE
|
|||
*/
|
||||
uint16_t r_page_servo_failsafe[IO_SERVO_COUNT] = { 0 };
|
||||
|
||||
void
|
||||
int
|
||||
registers_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num_values)
|
||||
{
|
||||
|
||||
|
@ -261,11 +261,13 @@ registers_set(uint8_t page, uint8_t offset, const uint16_t *values, unsigned num
|
|||
/* iterate individual registers, set each in turn */
|
||||
while (num_values--) {
|
||||
if (registers_set_one(page, offset, *values))
|
||||
break;
|
||||
return -1;
|
||||
offset++;
|
||||
values++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -451,6 +453,14 @@ registers_set_one(uint8_t page, uint8_t offset, uint16_t value)
|
|||
/* case PX4IO_RC_PAGE_CONFIG */
|
||||
}
|
||||
|
||||
case PX4IO_PAGE_TEST:
|
||||
switch (offset) {
|
||||
case PX4IO_P_TEST_LED:
|
||||
LED_AMBER(value & 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -51,17 +51,28 @@
|
|||
#include <up_internal.h>
|
||||
#include <up_arch.h>
|
||||
#include <stm32_internal.h>
|
||||
#include <systemlib/hx_stream.h>
|
||||
#include <systemlib/perf_counter.h>
|
||||
|
||||
//#define DEBUG
|
||||
#include "px4io.h"
|
||||
|
||||
static volatile bool sending = false;
|
||||
|
||||
static void dma_callback(DMA_HANDLE handle, uint8_t status, void *arg);
|
||||
static perf_counter_t pc_rx;
|
||||
static perf_counter_t pc_errors;
|
||||
static perf_counter_t pc_ore;
|
||||
static perf_counter_t pc_fe;
|
||||
static perf_counter_t pc_ne;
|
||||
static perf_counter_t pc_regerr;
|
||||
|
||||
static void rx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg);
|
||||
static void tx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg);
|
||||
static DMA_HANDLE tx_dma;
|
||||
static DMA_HANDLE rx_dma;
|
||||
|
||||
static int serial_interrupt(int irq, void *context);
|
||||
static void dma_reset(void);
|
||||
|
||||
#define MAX_RW_REGS 32 // by agreement w/FMU
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
@ -90,6 +101,13 @@ static struct IOPacket dma_packet;
|
|||
void
|
||||
interface_init(void)
|
||||
{
|
||||
pc_rx = perf_alloc(PC_COUNT, "rx count");
|
||||
pc_errors = perf_alloc(PC_COUNT, "errors");
|
||||
pc_ore = perf_alloc(PC_COUNT, "overrun");
|
||||
pc_fe = perf_alloc(PC_COUNT, "framing");
|
||||
pc_ne = perf_alloc(PC_COUNT, "noise");
|
||||
pc_regerr = perf_alloc(PC_COUNT, "regerr");
|
||||
|
||||
/* allocate DMA */
|
||||
tx_dma = stm32_dmachannel(PX4FMU_SERIAL_TX_DMA);
|
||||
rx_dma = stm32_dmachannel(PX4FMU_SERIAL_RX_DMA);
|
||||
|
@ -103,38 +121,37 @@ interface_init(void)
|
|||
rCR2 = 0;
|
||||
rCR3 = 0;
|
||||
|
||||
/* clear status/errors */
|
||||
(void)rSR;
|
||||
(void)rDR;
|
||||
|
||||
/* configure line speed */
|
||||
uint32_t usartdiv32 = PX4FMU_SERIAL_CLOCK / (PX4FMU_SERIAL_BITRATE / 2);
|
||||
uint32_t mantissa = usartdiv32 >> 5;
|
||||
uint32_t fraction = (usartdiv32 - (mantissa << 5) + 1) >> 1;
|
||||
rBRR = (mantissa << USART_BRR_MANT_SHIFT) | (fraction << USART_BRR_FRAC_SHIFT);
|
||||
|
||||
/* connect our interrupt */
|
||||
irq_attach(PX4FMU_SERIAL_VECTOR, serial_interrupt);
|
||||
up_enable_irq(PX4FMU_SERIAL_VECTOR);
|
||||
|
||||
/* enable UART and DMA */
|
||||
rCR3 = USART_CR3_DMAR | USART_CR3_DMAT;
|
||||
rCR1 = USART_CR1_RE | USART_CR1_TE | USART_CR1_UE;
|
||||
/*rCR3 = USART_CR3_EIE; */
|
||||
rCR1 = USART_CR1_RE | USART_CR1_TE | USART_CR1_UE /*| USART_CR1_IDLEIE*/;
|
||||
|
||||
/* configure DMA */
|
||||
stm32_dmasetup(
|
||||
tx_dma,
|
||||
(uint32_t)&rDR,
|
||||
(uint32_t)&dma_packet,
|
||||
sizeof(dma_packet),
|
||||
DMA_CCR_DIR |
|
||||
DMA_CCR_MINC |
|
||||
DMA_CCR_PSIZE_8BITS |
|
||||
DMA_CCR_MSIZE_8BITS);
|
||||
#if 0 /* keep this for signal integrity testing */
|
||||
for (;;) {
|
||||
while (!(rSR & USART_SR_TXE))
|
||||
;
|
||||
rDR = 0xfa;
|
||||
while (!(rSR & USART_SR_TXE))
|
||||
;
|
||||
rDR = 0xa0;
|
||||
}
|
||||
#endif
|
||||
|
||||
stm32_dmasetup(
|
||||
rx_dma,
|
||||
(uint32_t)&rDR,
|
||||
(uint32_t)&dma_packet,
|
||||
sizeof(dma_packet),
|
||||
DMA_CCR_MINC |
|
||||
DMA_CCR_PSIZE_8BITS |
|
||||
DMA_CCR_MSIZE_8BITS);
|
||||
|
||||
/* start receive DMA ready for the first packet */
|
||||
stm32_dmastart(rx_dma, dma_callback, NULL, false);
|
||||
/* configure RX DMA and return to listening state */
|
||||
dma_reset();
|
||||
|
||||
debug("serial init");
|
||||
}
|
||||
|
@ -146,27 +163,36 @@ interface_tick()
|
|||
}
|
||||
|
||||
static void
|
||||
dma_callback(DMA_HANDLE handle, uint8_t status, void *arg)
|
||||
tx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg)
|
||||
{
|
||||
if (!(status & DMA_STATUS_TCIF)) {
|
||||
/* XXX what do we do here? it's fatal! */
|
||||
return;
|
||||
}
|
||||
|
||||
/* if this is transmit-complete, make a note */
|
||||
if (handle == tx_dma) {
|
||||
sending = false;
|
||||
return;
|
||||
}
|
||||
sending = false;
|
||||
rCR3 &= ~USART_CR3_DMAT;
|
||||
}
|
||||
|
||||
static void
|
||||
rx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg)
|
||||
{
|
||||
/* we just received a request; sort out what to do */
|
||||
|
||||
rCR3 &= ~USART_CR3_DMAR;
|
||||
|
||||
/* work out how big the packet actually is */
|
||||
//unsigned rx_length = sizeof(IOPacket) - stm32_dmaresidual(rx_dma);
|
||||
|
||||
/* XXX implement check byte */
|
||||
/* XXX if we care about overruns, check the UART received-data-ready bit */
|
||||
|
||||
perf_count(pc_rx);
|
||||
|
||||
/* default to not sending a reply */
|
||||
bool send_reply = false;
|
||||
if (dma_packet.count & PKT_CTRL_WRITE) {
|
||||
|
||||
dma_packet.count &= ~PKT_CTRL_WRITE;
|
||||
|
||||
/* it's a blind write - pass it on */
|
||||
registers_set(dma_packet.page, dma_packet.offset, &dma_packet.regs[0], dma_packet.count);
|
||||
if (registers_set(dma_packet.page, dma_packet.offset, &dma_packet.regs[0], dma_packet.count))
|
||||
perf_count(pc_regerr);
|
||||
|
||||
} else {
|
||||
|
||||
/* it's a read - get register pointer for reply */
|
||||
|
@ -189,9 +215,94 @@ dma_callback(DMA_HANDLE handle, uint8_t status, void *arg)
|
|||
}
|
||||
|
||||
/* re-set DMA for reception first, so we are ready to receive before we start sending */
|
||||
stm32_dmastart(rx_dma, dma_callback, NULL, false);
|
||||
/* XXX latency here could mean loss of back-to-back writes; do we want to always send an ack? */
|
||||
/* XXX always sending an ack would simplify the FMU side (always wait for reply) too */
|
||||
dma_reset();
|
||||
|
||||
/* if we have a reply to send, start that now */
|
||||
if (send_reply)
|
||||
stm32_dmastart(tx_dma, dma_callback, NULL, false);
|
||||
if (send_reply) {
|
||||
stm32_dmasetup(
|
||||
tx_dma,
|
||||
(uint32_t)&rDR,
|
||||
(uint32_t)&dma_packet,
|
||||
sizeof(dma_packet), /* XXX cut back to actual transmit size */
|
||||
DMA_CCR_DIR |
|
||||
DMA_CCR_MINC |
|
||||
DMA_CCR_PSIZE_8BITS |
|
||||
DMA_CCR_MSIZE_8BITS);
|
||||
sending = true;
|
||||
stm32_dmastart(tx_dma, tx_dma_callback, NULL, false);
|
||||
rCR3 |= USART_CR3_DMAT;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
serial_interrupt(int irq, void *context)
|
||||
{
|
||||
uint32_t sr = rSR; /* get UART status register */
|
||||
|
||||
/* handle error/exception conditions */
|
||||
if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_IDLE)) {
|
||||
/* read DR to clear status */
|
||||
(void)rDR;
|
||||
} else {
|
||||
ASSERT(0);
|
||||
}
|
||||
|
||||
if (sr & (USART_SR_ORE | /* overrun error - packet was too big for DMA or DMA was too slow */
|
||||
USART_SR_NE | /* noise error - we have lost a byte due to noise */
|
||||
USART_SR_FE)) { /* framing error - start/stop bit lost or line break */
|
||||
|
||||
perf_count(pc_errors);
|
||||
if (sr & USART_SR_ORE)
|
||||
perf_count(pc_ore);
|
||||
if (sr & USART_SR_NE)
|
||||
perf_count(pc_ne);
|
||||
if (sr & USART_SR_FE)
|
||||
perf_count(pc_fe);
|
||||
|
||||
/* reset DMA state machine back to listening-for-packet */
|
||||
dma_reset();
|
||||
|
||||
/* don't attempt to handle IDLE if it's set - things went bad */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sr & USART_SR_IDLE) {
|
||||
|
||||
/* XXX if there was DMA transmission still going, this is an error */
|
||||
|
||||
/* stop the receive DMA */
|
||||
stm32_dmastop(rx_dma);
|
||||
|
||||
/* and treat this like DMA completion */
|
||||
rx_dma_callback(rx_dma, DMA_STATUS_TCIF, NULL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
dma_reset(void)
|
||||
{
|
||||
rCR3 &= ~(USART_CR3_DMAT | USART_CR3_DMAR);
|
||||
|
||||
|
||||
/* kill any pending DMA */
|
||||
stm32_dmastop(tx_dma);
|
||||
stm32_dmastop(rx_dma);
|
||||
|
||||
/* reset the RX side */
|
||||
stm32_dmasetup(
|
||||
rx_dma,
|
||||
(uint32_t)&rDR,
|
||||
(uint32_t)&dma_packet,
|
||||
sizeof(dma_packet),
|
||||
DMA_CCR_MINC |
|
||||
DMA_CCR_PSIZE_8BITS |
|
||||
DMA_CCR_MSIZE_8BITS);
|
||||
|
||||
/* start receive DMA ready for the next packet */
|
||||
stm32_dmastart(rx_dma, rx_dma_callback, NULL, false);
|
||||
rCR3 |= USART_CR3_DMAR;
|
||||
}
|
Loading…
Reference in New Issue