Page MenuHomec4science

dma_spi.c
No OneTemporary

File Metadata

Created
Sun, Jun 30, 18:32

dma_spi.c

/*
* dma_spi.c
*
* Copyright (c) Alexandre Tuleu
* EPFL Biorobotics Laboratory (http://biorob.epfl.ch)
* EPFL Ecole Polytechnique Federale de Lausanne (http://www.epfl.ch)
*
* * This program 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 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/**
* \file dma_sbcp.c
* DMA management for spi communications
* \author Alexandre Tuleu
*/
#include <p33Fxxxx.h>
#include "dma_spi.h"
#include "timer.h"
#include "misc.h"
#include "control_table.h"
#include "sbcp.h"
/*******************************************************************************
*
* Module data variables
*
******************************************************************************/
DMA_SPI_data dma_spi;
DMA_SPI_ME_rx_buffer dma_spi_me_rx_buffer __attribute__((space(dma)));
/*******************************************************************************
*
* Interruption
*
******************************************************************************/
/**
* Interruption when the SPI 1 finished its reading
*/
void __attribute__((__interrupt__ , no_auto_psv)) _DMA2Interrupt(){
dma_spi.ME_rx_state = DMA_SPI_ME_DATA_READY_TO_BE_PROCESSED;
SPI_ME_STOP_TRANSFER;
//clear the interruption flag
IFS1bits.DMA2IF = 0;
}
/*******************************************************************************
*
* Private functions
*
******************************************************************************/
//Initializes the dma channel for SPI recpetions
void spi_dma_init() {
//Use DMA channel 2 for reading SPI 1
DMA2CONbits.CHEN = 0;//disable channel 2, will be enabled when needed.
DMA2CONbits.SIZE = 0; //Word transfer enabled
DMA2CONbits.DIR = 0; //from device to ram
DMA2CONbits.HALF = 0; //inetrrupt when transfer is finished
DMA2CONbits.NULLW = 1; //Null write mode enabled for DMA Master RX only
DMA2CONbits.AMODE = 0b00; //Register indirect with post-increment
DMA2CONbits.MODE = 0b01; //One - shot mode, Ping - Pong disabled
DMA2STA = __builtin_dmaoffset(dma_spi_me_rx_buffer.w);
//no need to set DMA2STB , since no Ping-Pong
DMA2PAD = (volatile unsigned int ) &SPI1BUF;
DMA2REQ = 0x000A;
DMA2CNT = 3; //transfer 4 word, so 8 bytes so 64 bits
IFS1bits.DMA2IF = 0;//clear DMA2 Interrupt flag
IEC1bits.DMA2IE = 1; //enable DMA2 Interrupt flag
}
/*******************************************************************************
*
* Public functions
*
******************************************************************************/
/**
* Used to start the reading of SPI device. Reading takes time, so should be
* launched beofre motor control. Evenetually makes this function inline to
* speed up (a little) the process.
*/
void spi_start_reading(){
//start the reading of magnetic encoders.
dma_spi.ME_rx_state = DMA_SPI_ME_WAITING_FOR_DEVICES;
DMA2CONbits.CHEN = 1; //enable the channel, transfer will not start
//until something is written to SPI1BUF
SPI_ME_START_TRANSFER;
TIMER_2_START; //the interruption will start the actual transfer.
}
/**
* Used to process the data that comes from spi bus.
*/
void spi_main(){
//check if receivingg is finished
if(dma_spi.ME_rx_state == DMA_SPI_ME_DATA_READY_TO_BE_PROCESSED) {
//we assume that the parity is always correct.
/// \todo : check the parity of the data, buts it's rather complicated.
//this status flags are initialized with the magnetic amplitude values
unsigned char q1_status = (dma_spi_me_rx_buffer.w[1] & 0xc000) >> 9;
unsigned char q2_status = (dma_spi_me_rx_buffer.w[2] & 0x1800) >> 6;
unsigned char q3_status = (dma_spi_me_rx_buffer.w[3] & 0x0300) >> 3;
//check if Q1 data is correct
if( !(dma_spi_me_rx_buffer.b.Q1_OCF) //algorithm was unfinsihed
|| (dma_spi_me_rx_buffer.b.Q1_LIN) //linearity error
|| (dma_spi_me_rx_buffer.b.Q1_COF) //filtering error
|| q1_status == 0x60 ) { //magnetic amplitude error
q1_status |= 0x80;
}
control_table[A_MDRV_ME_Q1_POSITION].c[LOW_BYTE] =
dma_spi_me_rx_buffer.b.Q1_ENC_DATA_LOW;
//if previous data was invalid, this will erase this statement
control_table[A_MDRV_ME_Q1_POSITION].c[HIGH_BYTE] =
dma_spi_me_rx_buffer.b.Q1_ENC_DATA_HIGH | q1_status;
//check if Q2 data is correct
if( !(dma_spi_me_rx_buffer.b.Q2_OCF) //algorithm was unfinsihed
|| (dma_spi_me_rx_buffer.b.Q2_LIN) //linearity error
|| (dma_spi_me_rx_buffer.b.Q2_COF) //filtering error
|| q2_status == 0x60 ) { //magnetic amplitude error
q2_status |=0x80;
}
control_table[A_MDRV_ME_Q2_POSITION].c[LOW_BYTE] =
dma_spi_me_rx_buffer.b.Q2_ENC_DATA_LOW;
//this statement erase previous status value
control_table[A_MDRV_ME_Q2_POSITION].c[HIGH_BYTE] =
dma_spi_me_rx_buffer.b.Q2_ENC_DATA_HIGH | q2_status;
//check if Q3 data is correct
if( !(dma_spi_me_rx_buffer.b.Q3_OCF) //algorithm was unfinsihed
|| (dma_spi_me_rx_buffer.b.Q3_LIN) //linearity error
|| (dma_spi_me_rx_buffer.b.Q3_COF) //filtering error
|| q3_status == 0x60 ) { //magnetic amplitude error
q3_status |=0x80;
}
//the lower byte is cut in half here
control_table[A_MDRV_ME_Q3_POSITION].c[LOW_BYTE] =
dma_spi_me_rx_buffer.b.Q3_ENC_DATA_LOW
+ (dma_spi_me_rx_buffer.b.Q3_ENC_DATA_MID << 3);
//if previous data was invalid, this will erase this statement
control_table[A_MDRV_ME_Q3_POSITION].c[HIGH_BYTE] =
dma_spi_me_rx_buffer.b.Q3_ENC_DATA_HIGH | q3_status;
//we getted some new value to send, so we mark it :
sbcp.bus_low_latency_flags |= SBCP_LL_TX_IS_AVAILABLE;
//we have readen the data, nothing more to do
dma_spi.ME_rx_state = DMA_SPI_ME_IDLE;
}
}
/**
* Used to init SPI communications properly
*/
void spi_init(){
//Initialization of the control structures
dma_spi.ME_rx_state = DMA_SPI_ME_IDLE;
//clear the magnetic encoders buffer
dma_spi_me_rx_buffer.w[0] = 0x0000;//clear the whole word
dma_spi_me_rx_buffer.w[1] = 0x0000;//clear the whole word
dma_spi_me_rx_buffer.w[2] = 0x0000;//clear the whole word
dma_spi_me_rx_buffer.w[3] = 0x0000;//clear the whole word
//initilaization of the SPI modules
//SPI 1 is for magentic encoders :
IEC0bits.SPI1IE = 0; //disable interrupt. This is needed because we use DMA
IFS0bits.SPI1IF = 0; //clear the interrupt flag.
SPI1CON1bits.DISSCK = 0; //Us the clock
SPI1CON1bits.DISSDO = 1; //Disable data output. This is not needed by the application, no pin are routed
SPI1CON1bits.MODE16 = 1; //Transmit word. Rx buffer is in byte, but we don't care because we are transmitting an even number of byte
SPI1CON1bits.SMP = 0; //data is sampled at middle of clock time
SPI1CON1bits.CKE = 1; //clock cycle start when going from active to idle clock state.
SPI1CON1bits.CKP = 1; //clock idle state is at high level
SPI1CON1bits.MSTEN = 1; //enable master mode
//Choose a clock frequency of 625 kHz, max accepted by AS5045 is 1Mhz
SPI1CON1bits.SPRE = 0b111; //Select a secondary prescaler of 1:1
SPI1CON1bits.PPRE = 0b00 ; //select a primary prescaler of 64:1
SPI1CON2bits.FRMEN = 0; //No frame support
SPI1STATbits.SPIEN = 1; //Enable SPI 1 module
spi_dma_init();
}

Event Timeline