Page MenuHomec4science

dma_sbcp_master.c
No OneTemporary

File Metadata

Created
Mon, Dec 2, 05:07

dma_sbcp_master.c

/*
* dma_sbcp.c
*
* Copyright (c) 2011 Alexandre Tuleu
*
*/
#include <p33Fxxxx.h>
#include "dma_sbcp.h"
#include "sbcp.h"
#include "config.h"
#include "timer.h"
#include "port.h"
//#include "string.h"
//note: now dma for sbcp buffer are allocated in dma_memory_mapping_sbcp.c module
volatile DMA_SBCP_data dma_sbcp;
/*
DMA_packet_tx_queue dma_usb_tx_queue = {
0, //head
0, //tail
0, //nb_packet
{0,0,0,0}, //data_dma
{0,0,0,0} //data_cpu
};
DMA_packet_tx_queue dma_bus_tx_queue = {
0, //head
0, //tail
0, //nb_packet
{0,0,0,0}, //data_dma
{0,0,0,0} //data_cpu
};
*/
/* Interruption for the first dma channel.*/
void __attribute__((__interrupt__ , no_auto_psv)) _DMA0Interrupt(void) {
switch (dma_sbcp.bus_rx_state) {
case DMA_WAIT_FOR_HEADER_BYTE : {
if (*(dma_sbcp.current_bus_rx_packet) != 0x00ff) {
//Not an header byte, we reinitiniatlize the channel
DMA0CONbits.CHEN = 0;
DMA0CONbits.CHEN = 1;
} else {
DMA_BUS_CHANNEL_CONFIG_GET_END_HEADER;
}
DMA_BUS_ENABLE_ERR_DETECTION;
break;
}
case DMA_WAIT_FOR_FULL_HEADER : {
DMA_BUS_CHANNEL_CONFIG_GET_END_PACKET;
dma_sbcp.packet_states[dma_sbcp.bus_rx_packet] = SBCP_FEEDBACK_DEST_AND_SIZE_KNOWN;
break;
}
case DMA_WAIT_FOR_FULL_PACKET : {
dma_sbcp.bus_rx_state = DMA_WAIT_FOR_HEADER_BYTE;
PORT_RS485_TAKE_DRIVE();
TIMER_4_STOP_AND_CLEAR();
///remove any problem with interruption, if one has occured while beeing
///here
dma_sbcp.bus_rx_error &= ~(SBCP_COM_ERROR_CODE_BUS_TIMEOUT);
//we received a new packet from host, let it specify to the CPU
//specify to the CPU we got a packet for him
dma_sbcp.bus_rx_state = DMA_NO_RECEPTION;
dma_sbcp.bus_tx_state = SBCP_IDLE;
if (dma_sbcp.usb_tx_state == SBCP_TX_UNFINISHED_PACKET) {
dma_sbcp.usb_tx_state = SBCP_TX_FINISHED_PACKET;
}
//only change the state if not already treating it
if (dma_sbcp.packet_states[dma_sbcp.bus_rx_packet] == SBCP_FEEDBACK_DEST_AND_SIZE_KNOWN) {
dma_sbcp.packet_states[dma_sbcp.bus_rx_packet] =
SBCP_FEEDBACK_FULLY_RECEIVED;
}
// as a safety measure, we disable the interrupt. Indead, we
// have received one packet, we could not receive another one
// until another is transmitted
IEC0bits.DMA0IE = 0;
break;
}
default:
break;
}
//clear the interrupt flag !!
IFS0bits.DMA0IF = 0;
}
//so this f******** DMA is firing its interruption when it finished transfers
// *NOT* when the transfer is DONE ! So the situation is a bit tricky ....
// my idea : enable UART TX interruption configured to fore when the buffer is
//finished
void __attribute__((__interrupt__ , no_auto_psv)) _DMA1Interrupt(void) {
IEC0bits.DMA0IE = 0;
U1STAbits.UTXISEL0 = 1; //interruption when buffer is empty
IFS0bits.U1TXIF = 0; //yes it is set since we finished to transfer the data
IEC0bits.U1TXIE = 1; //enable interruption
IFS0bits.DMA1IF = 0;
};//just increment the packet aueue
void __attribute__((__interrupt__, no_auto_psv)) _U1TXInterrupt(void) {
//PR4 = (FCY/FSBCPT -1);
TIMER_4_START();
dma_sbcp.packet_states[dma_sbcp.bus_rx_packet] = SBCP_WAIT_FOR_FEEDBACK;
//disable error detection when opening the bus, as a bad header could show up !
DMA_BUS_DISABLE_ERR_DETECTION;
//even disable UART 1, we must not read any bad packet
U1MODEbits.UARTEN = 0;
U1STAbits.UTXEN = 0;
PORT_RS485_RELEASE_DRIVE();
// PORT_RS485_DRIVER_DISABLE;
// PORT_RS485_RECEIVER_ENABLE;
U1MODEbits.UARTEN = 1;
U1STAbits.UTXEN = 1;
DMA_INIT_BUS_RX;
dma_sbcp.bus_tx_state = SBCP_HALF_DUPLEX_WAITING_RESPONSE;
//disable UART 1 TX interrupt
IEC0bits.U1TXIE = 0;
U1STAbits.UTXISEL0 = 0; //Interruption every char !
IFS0bits.U1TXIF = 0; //clear interrupt !
//re-enable interuption for transmission :
IFS0bits.DMA0IF = 0;
IEC0bits.DMA0IE = 1;
};
void __attribute__((__interrupt__ , no_auto_psv)) _DMA2Interrupt(void) {
switch (dma_sbcp.usb_rx_state) {
case DMA_WAIT_FOR_HEADER_BYTE : {
if(*(dma_sbcp.current_usb_rx_packet) != 0X00ff) {
DMA2CONbits.CHEN = 0;
DMA2CONbits.CHEN = 1;
} else {
DMA_USB_CHANNEL_CONFIG_GET_END_HEADER;
TIMER_2_START();
//increment packet to reserve again some memory
}
break;
}
case DMA_WAIT_FOR_FULL_HEADER :{
DMA_USB_CHANNEL_CONFIG_GET_END_PACKET;
dma_sbcp.packet_states[dma_sbcp.rx_queue.tail]
= SBCP_FORWARD_DEST_AND_SIZE_KNOWN;
break;
}
case DMA_WAIT_FOR_FULL_PACKET : {
//the state of the packet may already have been choosen
if(dma_sbcp.packet_states[dma_sbcp.rx_queue.tail] == SBCP_FORWARD_DEST_AND_SIZE_KNOWN){
dma_sbcp.packet_states[dma_sbcp.rx_queue.tail] = SBCP_FORWARD_READY_TO_TREAT;
}
if (DMA_PACKET_QUEUE_FULL(dma_sbcp.rx_queue)) {
dma_sbcp.usb_rx_state = DMA_OVERFLOW_PENDING;
DMA2CONbits.CHEN = 0;
} else {
DMA_INIT_USB_RX;
}
TIMER_2_STOP_AND_CLEAR();
// remove any problem regarding timer interruption, we clear
// interruption flags, that may be setted if we getted any
// interruption while treating this one.
IFS0bits.T2IF = 0;
dma_sbcp.usb_rx_error &= ~(SBCP_COM_ERROR_CODE_USB_TIMEOUT);
if(dma_sbcp.bus_tx_state == SBCP_TX_UNFINISHED_PACKET){
dma_sbcp.bus_tx_state = SBCP_TX_FINISHED_PACKET;
}
break;
}
default:
break;
}
//clear the interrupt flag !!
IFS1bits.DMA2IF = 0;
}
void __attribute__((__interrupt__ , no_auto_psv)) _DMA3Interrupt(void) {
//clear the state of the current packet
dma_sbcp.packet_flags[dma_sbcp.rx_queue.head] = SBCP_UNCHECKED;
dma_sbcp.packet_states[dma_sbcp.rx_queue.head] = SBCP_INEXISTANT;
DMA_PACKET_QUEUE_INCREMENT_HEAD(dma_sbcp.rx_queue);
dma_sbcp.usb_tx_state = SBCP_IDLE;
IFS2bits.DMA3IF = 0; //clear interrupt !
};
void dma_sbcp_init(){
//initialize data
dma_sbcp.usb_rx_state = DMA_NO_RECEPTION;
dma_sbcp.bus_rx_state = DMA_NO_RECEPTION;
dma_sbcp.usb_tx_state = SBCP_IDLE;
dma_sbcp.bus_tx_state = SBCP_IDLE;
DMA_PACKET_QUEUE_SET_EMPTY(dma_sbcp.rx_queue);
dma_sbcp.bus_rx_packet = dma_sbcp.rx_queue.head;
dma_sbcp.usb_rx_error = 0;
dma_sbcp.bus_rx_error = 0;
unsigned int i;
for(i = 0; i < DMA_PACKET_QUEUE_LENGTH; ++i){
dma_sbcp.packet_flags[i] = SBCP_UNCHECKED;
dma_sbcp.packet_states[i] = SBCP_INEXISTANT;
}
//initialize DMA 0 for BUS RX
DMA0CONbits.SIZE = 0; // use word
DMA0CONbits.DIR = 0; // from peripherical to RAM
DMA0CONbits.HALF = 0; // inetrrupt after all receive
DMA0CONbits.NULLW = 0; // non null write
DMA0CONbits.AMODE = 0; //indirect register with post increment
DMA0CONbits.MODE = 1; //One shot, no ping pong
DMA0CNT = 0; //1 transfers
DMA0PAD = (volatile unsigned int) &U1RXREG;
DMA0STA = DMA_PACKET_QUEUE_BUS_GET_DMA(dma_sbcp.rx_queue.head);
DMA0REQ = 0x000b; //UART 1 RX irq
IEC0bits.DMA0IE = 0;
IPC1bits.DMA0IP = 5;
IFS0bits.DMA0IF = 0; //clear DMA interrupt flag
IEC0bits.DMA0IE = 1; //enable dmao interrupt
DMA0CONbits.CHEN = 0; //disable channel 0
//activate DMA 0
//initialize DMA 1 for BUS TX
DMA1CONbits.SIZE = 0; //use word
DMA1CONbits.DIR = 1; //from RAM to periph
DMA1CONbits.HALF = 0; //interrupt after all received char
DMA1CONbits.NULLW = 0; //normal mode
DMA1CONbits.AMODE = 0; //indirect register with post increment
DMA1CONbits.MODE = 1; //One shot, no ping pong
DMA1CNT = 0; //1 byte, should be overrwriten when launching
DMA1PAD = (volatile unsigned int) &U1TXREG;
DMA1STA = 2052; //should be overwritten when launching, other wise will
//send zero
DMA1REQ = 0x000c; //UART 1 TX IRQ
IEC0bits.DMA1IE = 0;
IPC3bits.DMA1IP = 5;
IFS0bits.DMA1IF = 0; //clear DMA interrupt flag
IEC0bits.DMA1IE = 1; //ENABLE DMA1 INTERRUPT !!!!
//DISABLE CHANNEL, WILL BE CONFIGURED AND ENABLED WHEN NEEDED
DMA1CONbits.CHEN = 0;
//initialize DMA 2 for UART 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
DMA2CNT = 0; //1 transfers
DMA2PAD = (volatile unsigned int) &U2RXREG;
DMA2STA = DMA_PACKET_QUEUE_BUS_GET_DMA(dma_sbcp.rx_queue.head);
DMA2REQ = 0x001e; //UART 1 RX irq
IEC1bits.DMA2IE = 0;
IPC6bits.DMA2IP = 5;
IFS1bits.DMA2IF = 0; //clear DMA interrupt flag
IEC1bits.DMA2IE = 1; //enable dmao 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 received char
DMA3CONbits.NULLW = 0; //normal mode
DMA3CONbits.AMODE = 0; //indirect register with post increment
DMA3CONbits.MODE = 1; //One shot, no ping pong
DMA3CNT = 0; //1 byte, should be overrwriten when launching
DMA3PAD = (volatile unsigned int) &U2TXREG;
DMA3STA = 2052; //should be overwritten when launching
DMA3REQ = 0x001f; //UART 2 TX IRQ
IEC2bits.DMA3IE = 0;
IPC9bits.DMA3IP = 5;
IFS2bits.DMA3IF = 0; //clear DMA3 interrupt flag
IEC2bits.DMA3IE = 1; //ENABLE DMA3 INTERRUPT !!!!
//Enable channel
DMA3CONbits.CHEN = 0;
PORT_RS485_TAKE_DRIVE();
DMA_INIT_USB_RX;
}

Event Timeline