Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F92679962
sbcp_host_rx.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Fri, Nov 22, 17:14
Size
6 KB
Mime Type
text/x-c
Expires
Sun, Nov 24, 17:14 (2 d)
Engine
blob
Format
Raw Data
Handle
22485254
Attached To
R6617 Oncilla SBCP Master Firmware
sbcp_host_rx.c
View Options
#include "sbcp_host.h"
#include <sbcp-uc/buffers.h>
#include <sbcp-uc/uart.h>
#include "led.h"
volatile unsigned int __attribute__((space(dma))) host_rx_buffer[SBCP_RX_BUFFER_SIZE];
typedef enum host_rx_state {
HOST_RX_STATE_IDLE = 0,
HOST_RX_STATE_RX,
HOST_RX_STATE_OVERFLOW
} host_rx_state;
typedef struct host_rx_data {
host_rx_state state;
buffer_fifo data_fifo,ready_fifo;
packet_mdata pck_mdata[SBCP_FRAME_SIZE];
volatile packet_mdata * cur_pck;
} host_rx_data;
volatile host_rx_data host_rx;
void init_sbcp_host_rx_data(){
host_rx.state = HOST_RX_STATE_IDLE;
buffer_fifo_set_empty(host_rx.data_fifo);
buffer_fifo_set_empty(host_rx.ready_fifo);
unsigned int i;
for (i = 0; i < SBCP_FRAME_SIZE; ++i) {
host_rx.pck_mdata[i].data = &(host_rx_buffer[i * SBCP_PACKET_SIZE]);
host_rx.pck_mdata[i].dma_adr = __builtin_dmaoffset(host_rx_buffer) + i * SBCP_PACKET_SIZE * 2;
host_rx.pck_mdata[i].id = i;
pck_clean_mdata(&(host_rx.pck_mdata[i]));
}
host_rx.cur_pck = 0;
}
void init_sbcp_host_tx_data();
void init_dma_for_host_rx(){
//initialize DMA 2 for UART2 RX
DMA2CONbits.SIZE = 0; // use word
DMA2CONbits.DIR = 0; // from peripherical to RAM
DMA2CONbits.HALF = 0; // inetrrupt after all receive
DMA2CONbits.NULLW = 0; // non null write
DMA2CONbits.AMODE = 0; //indirect register with post increment
DMA2CONbits.MODE = 1; //One shot, no ping pong
DMA2PAD = (volatile unsigned int) &U2RXREG;
// Count and address will be enabled on demand
// DMA2CNT = 0; //1 transfers
// DMA2STA = 0;
DMA2REQ = 0x001e; //UART 2 RX irq
// IEC1bits.DMA2IE = 0;
// IPC6bits.DMA2IP = 5; //higher priority
IFS1bits.DMA2IF = 0; //clear DMA 2 interrupt flag
IEC1bits.DMA2IE = 1; //enable DMA 2 interrupt
DMA2CONbits.CHEN = 0; //enable channel 2
//initialize DMA 3 for BUS TX
DMA3CONbits.SIZE = 0; //use word
DMA3CONbits.DIR = 1; //from RAM to periph
DMA3CONbits.HALF = 0; //interrupt after all send char
DMA3CONbits.NULLW = 0; //normal mode
DMA3CONbits.AMODE = 0; //indirect register with post increment
DMA3CONbits.MODE = 1; //One shot, no ping pong
DMA3PAD = (volatile unsigned int) &U2TXREG;
DMA3REQ = 0x001f; //UART 2 TX IRQ
// IEC2bits.DMA3IE = 0;
// IPC9bits.DMA3IP = 5; //higher priority
IFS2bits.DMA3IF = 0; //clear DMA3 interrupt flag
IEC2bits.DMA3IE = 1; //ENABLE DMA3 INTERRUPT !!!!
}
void init_sbcp_host() {
init_sbcp_host_rx_data();
init_sbcp_host_tx_data();
// U2RX is on RP 12
uart_map_rx_input(UART_2,RP_12);
map_pin_to_periph_output(13,RP_U2TX);
init_uart_for_sbcp(UART_2,BAUDRATE,FCY);
init_dma_for_host_rx();
}
/**
* Initializes the reception of a new packet
*/
#define sbcp_start_host_rx() { \
DMA2CONbits.CHEN = 0; \
buffer_fifo_increment_tail(host_rx.data_fifo); \
host_rx.cur_pck = &(host_rx.pck_mdata[host_rx.data_fifo.tail]); \
DMA2STA = host_rx.cur_pck->dma_adr;\
DMA2CNT = 0; \
DMA2CONbits.CHEN = 1; \
pck_init_rx(host_rx.cur_pck); \
host_rx.state = HOST_RX_STATE_RX; \
} while(0)
#define SBCP_MAX_PAYLOAD_SIZE (SBCP_PACKET_SIZE - SBCP_HEADER_SIZE )
void __attribute__((__interrupt__ , no_auto_psv)) _DMA2Interrupt(void) {
volatile packet_mdata * pck = host_rx.cur_pck;
switch (pck->rx_state) {
case PCK_RX_WAIT_FOR_HEADER_BYTE : {
if(pck->data[SBCP_HEADER_POS] != 0X00ff) {
//simply restart the channel, do ont change state or report anything
DMA2CONbits.CHEN = 0;
DMA2CONbits.CHEN = 1;
} else {
// we disable channel for modification
DMA2CONbits.CHEN = 0;
// adds 2 to the channel address
DMA2STA += 2;
// we wait for 3 byte : class, id, size
DMA2CNT = 2;
//restart channel ASAP
DMA2CONbits.CHEN = 1;
pck_start_header_rx(pck);
}
break;
}
case PCK_RX_WAIT_FOR_FULL_HEADER :{
// we disable channel for modification
DMA2CONbits.CHEN = 0;
//last state read 3 byte
DMA2STA += 6;
//checks for the size
sbcp_payload_size length = pck_payload_size(pck);
if (length > SBCP_MAX_PAYLOAD_SIZE) {
length = SBCP_MAX_PAYLOAD_SIZE;
}
//final size is length + inst + cs
DMA2CNT = length + 1;
DMA2CONbits.CHEN = 1;
pck_start_data_rx(pck);
break;
}
case PCK_RX_WAIT_FOR_FULL_DATA : {
pck_finish_rx(pck);
buffer_fifo_increment_tail(host_rx.ready_fifo);
if (buffer_fifo_full(host_rx.data_fifo)) {
host_rx.state = HOST_RX_STATE_OVERFLOW;
DMA2CONbits.CHEN = 0;
} else {
sbcp_start_host_rx();
}
break;
}
default:
break;
}
//clear the interrupt flag !!
IFS1bits.DMA2IF = 0;
}
void sbcp_process_host_rx() {
//simple state machine
// disable race conditions code following the disable should be
// really small in case we are in HOST_RX_STATE_RX. so we just get
// the data we need and return
IEC1bits.DMA2IE = 0;
host_rx_state state = host_rx.state;
volatile packet_mdata * pck = host_rx.cur_pck;
IEC1bits.DMA2IE = 1;
switch(state) {
case HOST_RX_STATE_RX :
//this test is really complex actually
if ( pck_rx_timeouted(pck) ) {
// now is the tricky part, because a race condition could
// occur, between the time we extract host_rx.cur_pck and
// now : the packet could have been received. So we need
// to perform a double check on the packet. But since we
// are in timeout we don't care about stopping the DMA for
// a long time.
IEC1bits.DMA2IE = 0;
// checks if the packet did have changed
if ( host_rx.cur_pck == pck ) {
static unsigned int nb_blink = 0;
led_blink_with_params(YELLOW,++nb_blink);
/* //disable DMA */
/* DMA2CONbits.CHEN = 0; */
/* //make sure the interruption will no show up again at restart */
/* IFS1bits.DMA2IF = 0; */
/* //we mark the packet timeouted */
/* pck->rx_error = PCK_RX_TERR; */
/* // make sure there is no overflow */
/* if ( buffer_fifo_full(host_rx.data_fifo) ) { */
/* host_rx.state = HOST_RX_STATE_OVERFLOW; */
/* } else { */
/* sbcp_start_host_rx(); */
/* } */
} // the packet have changed, we ignore the event
// re-enable interrupt
IEC1bits.DMA2IE = 1;
}
break;
case HOST_RX_STATE_OVERFLOW :
//no race condition possible :)
if ( !buffer_fifo_full(host_rx.data_fifo) ) {
host_rx.state = HOST_RX_STATE_IDLE;
}
break;
case HOST_RX_STATE_IDLE :
//no race condition possible :)
sbcp_start_host_rx();
break;
default :
//TODO report error
break;
}
}
volatile packet_mdata * next_host_packet() {
//avoid any race condition on the check;
IEC1bits.DMA2IE = 0;
uint8_t empty = buffer_fifo_empty(host_rx.ready_fifo);
IEC1bits.DMA2IE = 1;
if( empty ) {
return 0;
}
return &(host_rx.pck_mdata[host_rx.ready_fifo.head]);
}
void release_host_packet(volatile packet_mdata * pck) {
if ( pck->id != host_rx.ready_fifo.head ) {
//TODO : report error
return;
}
pck_clean_mdata(pck);
buffer_fifo_increment_head(host_rx.ready_fifo);
buffer_fifo_increment_head(host_rx.data_fifo);
}
Event Timeline
Log In to Comment