|
|
View previous topic :: View next topic |
Author |
Message |
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
DMA Driver for PIC18F26J11 and others |
Posted: Thu Feb 02, 2012 7:51 am |
|
|
I made a driver. I would like to share it with you.
I´ve not tested with interrupts yet.
I´ve not tested with full_duplex yet.
Code: | /*
PIC18F24J11 DMA driver
Arquivo : spi_dma_PIC18F24J11.c
Programador : Eduardo Guilherme Brandt
Criação : 31/01/2012 ( V 1.0 )
Contato : [email protected]
Histórico : Versão 1.0 - 31/01/2012
Last change : 01/02/2012
Functions :
// DEFINED MACROS
//
DMA_TXADDR(x) //This address is byte reversed. **Use this macro for load data.
DMA_RXADDR(x) //This address is byte reversed **Use this macro for load data.
DMA_DMABC(x) //This address is byte reversed **Use this macro for load data.
//
//
DMA_config(x); //DMA Control 1 config options
DMA_int_config(x); //configs DMACON2 register, that contains control bits for controlling interrupt generation and inter-byte delay behavior.
//
DMA_start(); //Start DMA transfer
DMA_is_busy(); //DMA is working
DMA_ended(); //DMA transfer ended
DMA_SET_FULL_DUPLEX(); //SPI DMA operates in Full-Duplex mode, data is simultaneously transmitted and received
DMA_SET_TX(); //DMA operates in Half-Duplex mode, data is transmitted only
DMA_SET_RX(); //DMA operates in Half-Duplex mode, data is transmitted only
DMA_write(DataSize, buffer); //Simple DMA Write and start transfer
DMA_read(DataSize, buffer); //Simple DMA Read and start transfer
//
// DEFINED FUNCTIONS
//
void DMA_default_config(); //Sets default DMA configuration
void DMA_write_block(int16 DataSize, int8 *buffer); //Write RAM data block using DMA
void DMA_read_block(int16 DataSize, int8 *buffer); //Read RAM data block using DMA
void DMA_spi_isr(void); //DMA interrupt service control(If DMA_use_ints is defined)
Further information:
Ps: It can be used for SPI or Ram memory copy(see uC datasheet)
#define DMA_use_ints //DMA interrupt service control enabled.
//Use and change the function "void DMA_spi_isr(void);" as needed
Registers-set:
see spi_dma.h header file
ps: For more details, see uC datasheet.
Config example: See in DMA_default_config() function
#define DMA_FULL_DUPLEX_MODE //Set to Full duplex mode
Eduardo Guilherme Brandt 31/01/2012 */
//////////////////////////////////////////////////////////////////////////////////////////
//
//
#ifdef DMA_use_ints
#warning spi DMA is using interrupt! (INT_SSP2)
#endif
//
//
//
#include <spi_dma_PIC18F24J11.h> //HEADER FILE
//
//
//
/*****************************************************************************************
******************************************************************************************
******************************************************************************************
*****************************************************************************************/
/*****************************************************************************************
******************************************************************************************
******************************************************************************************
*****************************************************************************************/
/*****************************************************************************************
******************************************************************************************
* DEFINED MACROS
* ex:
* DMA_start(); //Start DMA transfer
*/
#define DMA_TXADDR(x) DMA_TXADDRL=make8((int16)x,0); DMA_TXADDRH=make8((int16)x,1) //This address is byte reversed. **Use this macro for load data.
#define DMA_RXADDR(x) DMA_RXADDRL=make8((int16)x,0); DMA_RXADDRH=make8((int16)x,1) //This address is byte reversed **Use this macro for load data.
#define DMA_DMABC(x) DMA_DMABCL=make8((int16)x,0); DMA_DMABCH=make8((int16)x,1) //This address is byte reversed **Use this macro for load data.
//
#define DMA_config(x) DMA_DMACON1 = x //DMA Control 1 config options
#define DMA_int_config(x) DMA_DMACON2 = x //configs DMACON2 register, that contains control bits for controlling interrupt generation and inter-byte delay behavior.
#define DMA_start() DMA_DMAEN_=true //Start DMA transfer
#define DMA_is_busy() DMA_DMAEN_ //DMA is working
#define DMA_ended() !DMA_DMAEN_ //DMA transfer ended
#define DMA_SET_FULL_DUPLEX() DMA_FULL_DUPLEX_=true; DMA_TX_=false //SPI DMA operates in Full-Duplex mode, data is simultaneously transmitted and received
#define DMA_SET_TX() DMA_FULL_DUPLEX_=false; DMA_TX_=true //DMA operates in Half-Duplex mode, data is transmitted only
#define DMA_SET_RX() DMA_FULL_DUPLEX_=false; DMA_TX_=false //DMA operates in Half-Duplex mode, data is transmitted only
#define DMA_write(DataSize, buffer) DMA_SET_TX(); DMA_TXADDR(buffer); DMA_DMABC(DataSize-1); DMA_start() //Simple DMA Write and start transfer
#define DMA_read(DataSize, buffer) DMA_SET_RX(); DMA_RXADDR(buffer); DMA_DMABC(DataSize-1); DMA_start() //Simple DMA Read and start transfer
/*****************************************************************************************
******************************************************************************************
******************************************************************************************
*****************************************************************************************/
/*****************************************************************************************
******************************************************************************************
******************************************************************************************
*****************************************************************************************/
/*****************************************************************************************
******************************************************************************************
* Inicializa configuracao padrao nRF24L01+ (Ititializes default configuration for DMA)
* ex: DMA_default_config();
*/
void DMA_default_config() { //Sets default DMA configuration
#ifdef DMA_FULL_DUPLEX_MODE //Set to Full duplex mode
DMA_config(DMA_TXINC|DMA_RXINC|DMA_FULL_DUPLEX); //DMA Control 1 config options
DMA_int_config(0x00); //configs DMACON2 register, that contains control bits for controlling interrupt generation and inter-byte delay behavior.
#else
DMA_config(DMA_TXINC|DMA_RXINC|DMA_TX); //DMA Control 1 config options
DMA_int_config(0x00); //configs DMACON2 register, that contains control bits for controlling interrupt generation and inter-byte delay behavior.
#endif
}//
/*****************************************************************************************
******************************************************************************************
*
* DMA_write_block : Write RAM data block using DMA
* DMA_read_block : Read RAM data block using DMA
*
*
* Parameters:
*
* buffer : pointer to data array for sending or receiving using DMA
* DataSize : data size(number of bytes for writing or reading into "buffer" pointer)(Máx 1024 bytes)
*
* ex:
* int databuf[140]; //RAM DMA data pointer
* DMA_read_block(140, databuf); //reads 140 bytes using DMA
* while(DMA_is_busy()); //waits till DMA ended databuf reading
* DMA_write_block(140, databuf); //writes back the 140 bytes to SPI bus
* while(DMA_is_busy()); //waits till DMA ended databuf writing(sending)
*/
void DMA_write_block(int16 DataSize, char *buffer) { //Write RAM data block using DMA
if (DataSize>1024) DataSize=1024;
dma_write = true;
dma_busy = true;
#ifndef DMA_FULL_DUPLEX_MODE //If not seted to Full duplex mode
DMA_SET_TX(); //DMA operates in Half-Duplex mode, data is transmitted only
#endif
DataSize--;
DMA_TXADDR(buffer);
DMA_DMABC(DataSize); //write datasize -1(1 to 1024 bytes)
#ifdef DMA_use_ints
enable_interrupts(INT_SSP2);
#endif
DMA_start(); //Start DMA transfer
}
//
void DMA_read_block(int16 DataSize, char *buffer) { //Read RAM data block using DMA
if (DataSize>1024) DataSize=1024;
dma_write = false;
dma_busy = true;
#ifndef DMA_FULL_DUPLEX_MODE //If not seted to Full duplex mode
DMA_SET_RX(); //DMA operates in Half-Duplex mode, data is transmitted only
#endif
DataSize--;
DMA_RXADDR(buffer);
DMA_DMABC(DataSize); //write datasize -1(1 to 1024 bytes)
#ifdef DMA_use_ints
enable_interrupts(INT_SSP2);
#endif
DMA_start(); //Start DMA transfer
}
//
/*****************************************************************************************
******************************************************************************************
******************************************************************************************
*****************************************************************************************/
/*****************************************************************************************
******************************************************************************************
*
* DMA interrupt service control
*
*/
#INT_SSP2
void DMA_spi_isr(void) {
// int timeout=10;
if (!DMA_DMAEN_) {
disable_interrupts(INT_SSP2);
// If write mode
if (dma_write) {
delay_cycles(1); //do what you want to
spi_write2(0xFF); // 16 bit CRC MSB (ignored)
}
else {
delay_cycles(1); //do what you want to
}
delay_cycles(1); //do what you want to
dma_busy = false;
}
}//
|
And the header file:
Code: | // spi_dma.h for PIC18F24J11, by Eduardo Guilherme Brandt
//
#ifndef SPI_DMA
#define SPI_DMA
/***************************
Further information
- I/O PIN CONSIDERATIONS
When enabled, the SPI DMA module uses the MSSP2 module. All SPI related input and output signals related
to MSSP2 are routed through the Peripheral Pin Select module.
- RAM TO RAM COPY OPERATIONS
Although the SPI DMA module is primarily intended to be used for SPI communication purposes, the module
can also be used to perform RAM to RAM copy operations.
To do this, configure the module for Full-Duplex Master mode operation, but assign the SDO2 output
and SDI2 input functions onto the same RPn pin in the PPS module. This will allow the module to operate in
Loopback mode, providing RAM copy capability.
- IDLE AND SLEEP CONSIDERATIONS
The SPI DMA module remains fully functional when the microcontroller is in Idle mode.
During normal sleep, the SPI DMA module is not functional and should not be used. To avoid corrupting a
transfer, user firmware should be careful to make certain that pending DMA operations are complete by
polling the DMAEN bit in the DMACON1 register prior to putting the microcontroller into Sleep.
In SPI Slave modes, the MSSP2 module is capable of transmitting and/or receiving one byte of data while in
Sleep mode. This allows the SSP2IF flag in the PIR3 register to be used as a wake-up source. When the
DMAEN bit is cleared, the SPI DMA module is effectively disabled, and the MSSP2 module functions
normally, but without DMA capabilities. If the DMAEN bit is clear prior to entering Sleep, it is still possible to
use the SSP2IF as a wake-up source without any data loss.
Neither MSSP2 nor the SPI DMA module will provide any functionality in Deep Sleep. Upon exiting from
Deep Sleep, all of the I/O pins, MSSP2 and SPI DMA related registers will need to be fully reinitialized before
the SPI DMA module can be used again.
*/
// Definitions for SPI DMA transfer
#byte DMA_TXADDRH = 0x0F6A //SPI DMA Tranmsit Data Pointer High Byte ---- 0000 73
#byte DMA_TXADDRL = 0x0F6B //SPI DMA Tranmsit Data Pointer Low Byte 0000 0000 73
#byte DMA_RXADDRH = 0x0F68 //SPI DMA Receive Data Pointer High Byte ---- 0000 73
#byte DMA_RXADDRL = 0x0F69 //SPI DMA Receive Data Pointer Low Byte 0000 0000 73
#byte DMA_DMABCH = 0x0F66 //SPI DMA Receive Data Pointer High Byte
#byte DMA_DMABCL = 0x0F67 //SPI DMA Byte Count Low Byte 0000 0000 73
// Definitions for SPI DMA transfer
#byte DMA_DMACON1 = 0x0F88 //see DMACON1. DMA Control1 register options
#byte DMA_DMACON2 = 0x0F86 //see DMACON2. Contains control bits for controlling interrupt generation and inter-byte delay behavior. The INTLVL<3:0> bits are used to select when an SSP2IF interrupt should be generated.The function of the DLYCYC<3:0> bits depends on the SPI operating mode (Master/Slave), as well as the DLYINTEN setting.
#word DMA_TXADDR = 0x0F6A //**use DMA_TXADDR(x) for load data(byte reversed). SPI DMA Tranmsit Data Pointer(word)
#word DMA_RXADDR = 0x0F68 //**use DMA_RXADDR(x) for load data(byte reversed). SPI DMA Receive Data Pointer(word)
#word DMA_DMABC = 0x0F66 //**use DMA_DMABC(x) for load data(byte reversed). SPI DMA Data Size(word). (set value 0 to 1023 = 1 to 1024 bytes)
// DMACON1 bits
#bit DMA_SSCON1_ = DMA_DMACON1.7
#bit DMA_SSCON0_ = DMA_DMACON1.6
#bit DMA_TXINC_ = DMA_DMACON1.5
#bit DMA_RXINC_ = DMA_DMACON1.4
#bit DMA_FULL_DUPLEX_=DMA_DMACON1.3 //SPI DMA operates in Full-Duplex mode, data is simultaneously transmitted and received
#bit DMA_TX_ = DMA_DMACON1.2 //DMA operates in Half-Duplex mode, data is transmitted only
#bit DMA_DUPLEX1_ = DMA_DMACON1.3
#bit DMA_DUPLEX0_ = DMA_DMACON1.2
#bit DMA_DLYINTEN_ = DMA_DMACON1.1
#bit DMA_DMAEN_ = DMA_DMACON1.0
// Definitions for SPI2(not used)
#byte SSP2STAT = 0x0F73
#byte SSP2BUF = 0x0F75
#byte SSP2CON1 = 0x0F72
enum DMA_DMACON1_enum { //DMA Control1 register options
DMA_SSCON_32bits=0b11000000, //Used to control the SS(slave select pin). SS_DMA is asserted each 4 bytes transmitted; DLYINTEN is always reset low
DMA_SSCON_16bits=0b10000000, //Used to control the SS(slave select pin). SS_DMA is asserted each 2 bytes transmitted; DLYINTEN is always reset low
DMA_SSCON_8bits= 0b01000000, //Used to control the SS(slave select pin). SS_DMA is asserted each 1 byte transmitted; DLYINTEN is always reset low
DMA_TXINC = 0b00100000, //Allows the transmit address to increment as the transfer progresses. The transmit address is to be incremented from the initial value of TXADDR<11:0>
DMA_RXINC = 0b00010000, //Allows the receive address to increment as the transfer progresses. The received address is to be incremented from the initial value of RXADDR<11:0>
DMA_FULL_DUPLEX= 0b00001000, //SPI DMA operates in Full-Duplex mode, data is simultaneously transmitted and received
DMA_TX = 0b00000100, //DMA operates in Half-Duplex mode, data is transmitted only
DMA_RX = 0b00000000, //DMA operates in Half-Duplex mode, data is transmitted only
DMA_DLYINTEN = 0b00000010, //Delay Interrupt Enable bit. Enables the interrupt to be invoked after the number of SCK cycles specified in DLYCYC<2:0> has elapsed from the latest completed transfer. If interrupt is enabled, SSCON<1:0> must be set to ‘00’
DMA_DMAEN = 0b00000001}; //This bit is set by the users’ software to start the DMA operation. It is reset back to zero by the DMA engine when the DMA operation is completed or aborted. **To avoid possible data corruption, once the DMAEN bit is set, user firmware should not attempt to modify any of the MSSP2 or SPI DMA related registers, with the exception of the INTLVL bits in the DMACON2 register.
enum DMA_DMACON2_enum { //DMACON2 register contains control bits for controlling interrupt generation and inter-byte delay behavior. The INTLVL<3:0> bits are used to select when an SSP2IF interrupt should be generated.The function of the DLYCYC<3:0> bits depends on the SPI operating mode (Master/Slave), as well as the DLYINTEN setting.
DMA_DLYCYC3 = 0b10000000, //
DMA_DLYCYC2 = 0b01000000, //
DMA_DLYCYC1 = 0b00100000, //
DMA_DLYCYC0 = 0b00010000, //
DMA_INTLVL3 = 0b00001000, //
DMA_INTLVL2 = 0b00000100, //
DMA_INTLVL1 = 0b00000010, //
DMA_INTLVL0 = 0b00000001}; //
/*
In SPI Master mode, the DLYCYC<3:0> bits can be usedto control how much time the module will Idle between
bytes in a transfer. By default, the hardware requires a minimum delay of: 8 TCY for FOSC/4, 9 TCY for FOSC/16
and 15 TCY for FOSC/64. Additional delays can be added with the DLYCYC bits. In SPI Slave modes, the
DLYCYC<3:0> bits may optionally be used to trigger an additional time-out based interrupt.
DMA_DLYCYCLES(bits 3 to 0):
1111 = Delay time in number of instruction cycles is 2,048 cycles
1110 = Delay time in number of instruction cycles is 1,024 cycles
1101 = Delay time in number of instruction cycles is 896 cycles
1100 = Delay time in number of instruction cycles is 768 cycles
1011 = Delay time in number of instruction cycles is 640 cycles
1010 = Delay time in number of instruction cycles is 512 cycles
1001 = Delay time in number of instruction cycles is 384 cycles
1000 = Delay time in number of instruction cycles is 256 cycles
0111 = Delay time in number of instruction cycles is 128 cycles
0110 = Delay time in number of instruction cycles is 64 cycles
0101 = Delay time in number of instruction cycles is 32 cycles
0100 = Delay time in number of instruction cycles is 16 cycles
0011 = Delay time in number of instruction cycles is 8 cycles
0010 = Delay time in number of instruction cycles is 4 cycles
0001 = Delay time in number of instruction cycles is 2 cycles
0000 = Delay time in number of instruction cycles is 1 cycle
INTLVL<3:0>: Watermark Interrupt Enable bits
These bits specify the amount of remaining data yet to be transferred (transmitted and/or received)
upon which an interrupt is generated.
1111 = Amount of remaining data to be transferred is 576 bytes
1110 = Amount of remaining data to be transferred is 512 bytes
1101 = Amount of remaining data to be transferred is 448 bytes
1100 = Amount of remaining data to be transferred is 384 bytes
1011 = Amount of remaining data to be transferred is 320 bytes
1010 = Amount of remaining data to be transferred is 256 bytes
1001 = Amount of remaining data to be transferred is 192 bytes
1000 = Amount of remaining data to be transferred is 128 bytes
0111 = Amount of remaining data to be transferred is 67 bytes
0110 = Amount of remaining data to be transferred is 32 bytes
0101 = Amount of remaining data to be transferred is 16 bytes
0100 = Amount of remaining data to be transferred is 8 bytes
0011 = Amount of remaining data to be transferred is 4 bytes
0010 = Amount of remaining data to be transferred is 2 bytes
0001 = Amount of remaining data to be transferred is 1 byte
0000 = Transfer complete
For example, if DMACON2<3:0> = 0101(16 bytes remaining), the SSP2IF interrupt flag will
become set once DMABC reaches 00Fh. If user firmware then clears the SSP2IF interrupt flag, the flag
will not be set again by the hardware until after all bytes have been fully transmitted and the DMA
transaction is complete.
*/
int1 dma_write = false;
int1 dma_busy = false;
// int8 res1, res2;
|
[/code] _________________ Eduardo Guilherme Brandt |
|
|
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
|
Posted: Wed Feb 08, 2012 11:28 am |
|
|
Archere wrote: | Thanks for sharing this driver I'll try this driver if you have any more such drivers then share these with me. |
Happy for helping!
You can change others SPI drivers to accept DMA transfers.
I reached almost 740KBytes/S (PIC at 48MHz) reading from a FLASH memory.
It´s pretty good for a PIC uC!! It´s easy to use, but it´s a penny that PIC has just one DMA. But it´s good enough for small projects.
++++++++++++++++++++
Archere post deleted.
Reason: Spambot selling insurance in sigline link
Sorry.
- Forum Moderator
++++++++++++++++++++ _________________ Eduardo Guilherme Brandt |
|
|
hugo_br
Joined: 01 Aug 2011 Posts: 26 Location: BRAZIL
|
DMA com AD? |
Posted: Fri Feb 10, 2012 10:17 am |
|
|
Good afternoon Eduardo.
I'm trying to read 4 channels of AD DSPIC33FJ256GP506 simultaneously via DMA.
Or you need to make measurements of each channel in 1024 AD by a total of four channels of DMA read and play these on a SD card in an I2C memory.
Through the Example of DMA 4120 CCS could do a reading at a time, but I can not make 4 simultaneous readings. Do you think it would be possible? Would help with something? For I am crude in DMA!
I really appreciate the attention and help.
I look forward to a return.
Thank you, Hugo.
Now in Portguese:
Boa tarde Eduardo.
Vou escrever em Português mesmo!
Estou tentando ler 4 Canais do AD de um DSPIC33FJ256GP506 simultaneamente através de DMA.
Ou seja preciso fazer 1024 medições de cada canal AD totalizando 4 Canais através de DMA e jogar estas leitura em um SD CARD em um memória I2C.
Através do Exemplo de DMA do CCS 4.120 consegui fazer uma leitura por vez, mas não consigo fazer 4 leituras simultâneas. Você acha que isso seria possível? Teria como ajudar em algo? Pois sou crú em DMA!
Agradeço muito a atenção e ajuda.
Aguardo um retorno.
Grato, Hugo. |
|
|
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
|
Posted: Fri Feb 10, 2012 12:15 pm |
|
|
Dear Hugo,
I´ve not used DSPIC DMA yet*(Only PIC18F DMA). But you should see DSPIC33FJ256GP506 datasheet, because there are differences between part resources.
For example: PIC18F26J50 has no AD-DMA. Only SPI-DMA. But even SPI-DMA could be used for making RAM-to-RAM copy.
Another thing, PIC18F26J50 has only one DMA .
You should check all these parameters.
Another suggestion:
1 - You should post your questions in General CCS C Discussion Forum, not here. This is Code Library Forum.
2 - Post in English, so the community will help you!
3 - Use a debugger like "ICD2BR - Mosaico". Just look at it in google. It will help you very much! You can use it with MPLAB and CCS language. It works very well, even for DSPICs. CCS has also a very cheap debugger named "ICD-U64 In-Circuit Programmer/Debugger", but I´m not used yet. I´m going to buy it later.
Good luck!! _________________ Eduardo Guilherme Brandt |
|
|
hugo_br
Joined: 01 Aug 2011 Posts: 26 Location: BRAZIL
|
|
Posted: Fri Feb 10, 2012 1:07 pm |
|
|
Eduardo thank you for your help.
I posted several posts here at CCS Forum and getting no help yet. But I'm always trying.
Even so thank very much the support and attention.
Maybe one day I'm lucky.
Thank you, Hugo. |
|
|
zspikes
Joined: 10 Jan 2013 Posts: 7
|
|
Posted: Wed May 14, 2014 7:01 am |
|
|
Hi!! First of all, thanks a lot for sharing. This is very useful!
I have one question. How do you use it in a full duplex communication? You only execute the "write" command and receive it automatically?
thanks!!! |
|
|
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
|
Posted: Wed May 14, 2014 6:30 pm |
|
|
yes, you can use dma_write_block() and dma_read_block() functions, but, first #define DMA_FULL_DUPLEX_MODE
I´m sorry it was a lot of time I not used this driver anymore, and now I´ve not too much time for checking it. You´ll have to read by yourself the driver instructions.
good luck friend!! _________________ Eduardo Guilherme Brandt |
|
|
zspikes
Joined: 10 Jan 2013 Posts: 7
|
|
Posted: Thu May 15, 2014 7:27 am |
|
|
Ok, great! I'll study a little the code. Then I tell you how it went ;)
Thank you very much! |
|
|
zspikes
Joined: 10 Jan 2013 Posts: 7
|
|
Posted: Wed May 21, 2014 7:53 pm |
|
|
Hi Eduardo! I've read the whole chapter "SPI DMA Module" from the datasheet, and your code as well. I've made some modifications to adapt it to my needs. I hope you don't mind.
I post it in case someone needs it.
Cheers!
Here's the code:
Code: |
/*
PIC18F24J11 DMA driver
File : spi_dma_PIC18F24J11.c
Created by : Eduardo Guilherme Brandt
Modified by : Gerardo Daniel Cibeira
Created : 31/01/2012 ( V 1.0 )
Contact : [email protected]
Historic : Version 1.0 - 31/01/2012 Eduardo Guilherme Brandt
Version 1.1 - 19/05/2014 Gerardo Daniel Cibeira
*/
#include <dma.h> //HEADER FILE
/*****************************************************************************************
*
* DEFINED MACROS
*
******************************************************************************************/
#define DMA_TXADDR(x) DMA_TXADDRL=make8((int16)x,0); DMA_TXADDRH=make8((int16)x,1) //This address is byte reversed. **Use this macro for load data.
#define DMA_RXADDR(x) DMA_RXADDRL=make8((int16)x,0); DMA_RXADDRH=make8((int16)x,1) //This address is byte reversed **Use this macro for load data.
#define DMA_DMABC(x) DMA_DMABCL=make8((int16)x,0); DMA_DMABCH=make8((int16)x,1) //This address is byte reversed **Use this macro for load data.
#define setup_DMA(x) DMA_DMACON1 = x
#define setup_DMA_int(x) DMA_DMACON2 = x
#define DMA_start() DMA_DMAEN_ = 1 //Start DMA transfer
#define DMA_is_busy() DMA_DMAEN_ //DMA is working
#define DMA_ended() !DMA_DMAEN_ //DMA transfer ended
#define DMA_SET_FULL_DUPLEX() DMA_DUPLEX1_ = 1; DMA_DUPLEX0_ = 0
#define DMA_SET_TX() DMA_DUPLEX1_ = 0; DMA_DUPLEX0_ = 1
#define DMA_SET_RX() DMA_DUPLEX1_ = 0; DMA_DUPLEX0_ = 0
/*****************************************************************************************
*
* DMA_write : Write RAM data block using DMA
* DMA_read : Read RAM data block using DMA
* DMA_transfer : Does a fullduplex transfer using DMA
*
* Parameters:
*
* buffer : pointer to data array for sending or receiving using DMA
* DataSize : data size(number of bytes for writing or reading into "buffer" pointer)(Máx 1024 bytes)
*
******************************************************************************************/
void DMA_write(int16 DataSize, char *buffer) {
if (DataSize>1024) DataSize=1024;
DMA_SET_TX();
DMA_TXADDR(buffer);
DMA_DMABC(DataSize-1);
DMA_start();
}
void DMA_read(int16 DataSize, char *buffer) {
if (DataSize>1024) DataSize=1024;
DMA_SET_RX();
DMA_RXADDR(buffer);
DMA_DMABC(DataSize-1);
DMA_start();
}
void DMA_transfer(int16 DataSize, char *txbuffer, char *rxbuffer) {
if (DataSize>1024) DataSize=1024;
DMA_SET_FULL_DUPLEX();
DMA_RXADDR(rxbuffer);
DMA_TXADDR(txbuffer);
DMA_DMABC(DataSize-1);
DMA_start();
}
|
and the header file:
Code: |
/*
PIC18F24J11 DMA driver
File : spi_dma_PIC18F24J11.h
Created by : Eduardo Guilherme Brandt
Modified by : Gerardo Daniel Cibeira
Created : 31/01/2012 (v1.0)
Contact : [email protected]
Historic : Version 1.0 - 31/01/2012 Eduardo Guilherme Brandt
Version 1.1 - 19/05/2014 Gerardo Daniel Cibeira
*/
#ifndef SPI_DMA
#define SPI_DMA
/***************************
Further information
- I/O PIN CONSIDERATIONS
When enabled, the SPI DMA module uses the MSSP2 module. All SPI related input and output signals related
to MSSP2 are routed through the Peripheral Pin Select module.
- RAM TO RAM COPY OPERATIONS
Although the SPI DMA module is primarily intended to be used for SPI communication purposes, the module
can also be used to perform RAM to RAM copy operations.
To do this, configure the module for Full-Duplex Master mode operation, but assign the SDO2 output
and SDI2 input functions onto the same RPn pin in the PPS module. This will allow the module to operate in
Loopback mode, providing RAM copy capability.
- IDLE AND SLEEP CONSIDERATIONS
The SPI DMA module remains fully functional when the microcontroller is in Idle mode.
During normal sleep, the SPI DMA module is not functional and should not be used. To avoid corrupting a
transfer, user firmware should be careful to make certain that pending DMA operations are complete by
polling the DMAEN bit in the DMACON1 register prior to putting the microcontroller into Sleep.
In SPI Slave modes, the MSSP2 module is capable of transmitting and/or receiving one byte of data while in
Sleep mode. This allows the SSP2IF flag in the PIR3 register to be used as a wake-up source. When the
DMAEN bit is cleared, the SPI DMA module is effectively disabled, and the MSSP2 module functions
normally, but without DMA capabilities. If the DMAEN bit is clear prior to entering Sleep, it is still possible to
use the SSP2IF as a wake-up source without any data loss.
Neither MSSP2 nor the SPI DMA module will provide any functionality in Deep Sleep. Upon exiting from
Deep Sleep, all of the I/O pins, MSSP2 and SPI DMA related registers will need to be fully reinitialized before
the SPI DMA module can be used again.
*/
// Definitions for SPI DMA transfer
#byte DMA_TXADDRH = 0x0F6A //SPI DMA Tranmsit Data Pointer High Byte ---- 0000 73
#byte DMA_TXADDRL = 0x0F6B //SPI DMA Tranmsit Data Pointer Low Byte 0000 0000 73
#byte DMA_RXADDRH = 0x0F68 //SPI DMA Receive Data Pointer High Byte ---- 0000 73
#byte DMA_RXADDRL = 0x0F69 //SPI DMA Receive Data Pointer Low Byte 0000 0000 73
#byte DMA_DMABCH = 0x0F66 //SPI DMA Receive Data Pointer High Byte
#byte DMA_DMABCL = 0x0F67 //SPI DMA Byte Count Low Byte 0000 0000 73
// Definitions for SPI DMA transfer
#byte DMA_DMACON1 = 0x0F88 //see DMACON1. DMA Control1 register options
#byte DMA_DMACON2 = 0x0F86 //see DMACON2. Contains control bits for controlling interrupt generation and inter-byte delay behavior. The INTLVL<3:0> bits are used to select when an SSP2IF interrupt should be generated.The function of the DLYCYC<3:0> bits depends on the SPI operating mode (Master/Slave), as well as the DLYINTEN setting.
#word DMA_TXADDR = 0x0F6A //**use DMA_TXADDR(x) for load data(byte reversed). SPI DMA Tranmsit Data Pointer(word)
#word DMA_RXADDR = 0x0F68 //**use DMA_RXADDR(x) for load data(byte reversed). SPI DMA Receive Data Pointer(word)
#word DMA_DMABC = 0x0F66 //**use DMA_DMABC(x) for load data(byte reversed). SPI DMA Data Size(word). (set value 0 to 1023 = 1 to 1024 bytes)
// DMACON1 bits
#bit DMA_SSCON1_ = DMA_DMACON1.7
#bit DMA_SSCON0_ = DMA_DMACON1.6
#bit DMA_TXINC_ = DMA_DMACON1.5
#bit DMA_RXINC_ = DMA_DMACON1.4
#bit DMA_DUPLEX1_ = DMA_DMACON1.3
#bit DMA_DUPLEX0_ = DMA_DMACON1.2
#bit DMA_DLYINTEN_ = DMA_DMACON1.1
#bit DMA_DMAEN_ = DMA_DMACON1.0
//setup_DMA() defines
#define DMA_SSCON_4 0xC0 //Used to control the SS(slave select pin). SS_DMA is asserted each 4 bytes transmitted; DLYINTEN is always reset low
#define DMA_SSCON_2 0x80 //Used to control the SS(slave select pin). SS_DMA is asserted each 2 bytes transmitted; DLYINTEN is always reset low
#define DMA_SSCON_1 0x40 //Used to control the SS(slave select pin). SS_DMA is asserted each 1 byte transmitted; DLYINTEN is always reset low
#define DMA_TXINC 0x20 //Allows the transmit address to increment as the transfer progresses. The transmit address is to be incremented from the initial value of TXADDR<11:0>
#define DMA_RXINC 0x10 //Allows the receive address to increment as the transfer progresses. The received address is to be incremented from the initial value of RXADDR<11:0>
#define DMA_FULL_DUPLEX 0x08 //SPI DMA operates in Full-Duplex mode, data is simultaneously transmitted and received
#define DMA_TX 0x04 //DMA operates in Half-Duplex mode, data is transmitted only
#define DMA_RX 0x00 //DMA operates in Half-Duplex mode, data is transmitted only
#define DMA_DLYINTEN 0x02 //Delay Interrupt Enable bit. Enables the interrupt to be invoked after the number of SCK cycles specified in DLYCYC<2:0> has elapsed from the latest completed transfer. If interrupt is enabled, SSCON<1:0> must be set to ‘00’
#define DMA_DMAEN 0x01
//setup_DMA_int() defines
#define DMA_DLYCYC_2048 0xF0
#define DMA_DLYCYC_1024 0xE0
#define DMA_DLYCYC_896 0xD0
#define DMA_DLYCYC_768 0xC0
#define DMA_DLYCYC_640 0xB0
#define DMA_DLYCYC_512 0xA0
#define DMA_DLYCYC_384 0x90
#define DMA_DLYCYC_256 0x80
#define DMA_DLYCYC_128 0x70
#define DMA_DLYCYC_64 0x60
#define DMA_DLYCYC_32 0x50
#define DMA_DLYCYC_16 0x40
#define DMA_DLYCYC_8 0x30
#define DMA_DLYCYC_4 0x20
#define DMA_DLYCYC_2 0x10
#define DMA_DLYCYC_1 0x00
#define DMA_INTLVL_576 0x0F
#define DMA_INTLVL_512 0x0E
#define DMA_INTLVL_448 0x0D
#define DMA_INTLVL_384 0x0C
#define DMA_INTLVL_320 0x0B
#define DMA_INTLVL_256 0x0A
#define DMA_INTLVL_192 0x09
#define DMA_INTLVL_128 0x08
#define DMA_INTLVL_67 0x07
#define DMA_INTLVL_32 0x06
#define DMA_INTLVL_16 0x05
#define DMA_INTLVL_8 0x04
#define DMA_INTLVL_4 0x03
#define DMA_INTLVL_2 0x02
#define DMA_INTLVL_1 0x01
#define DMA_INTLVL_0 0x00
/*
In SPI Master mode, the DLYCYC<3:0> bits can be usedto control how much time the module will Idle between
bytes in a transfer. By default, the hardware requires a minimum delay of: 8 TCY for FOSC/4, 9 TCY for FOSC/16
and 15 TCY for FOSC/64. Additional delays can be added with the DLYCYC bits. In SPI Slave modes, the
DLYCYC<3:0> bits may optionally be used to trigger an additional time-out based interrupt.
DMA_DLYCYCLES(bits 3 to 0):
1111 = Delay time in number of instruction cycles is 2,048 cycles
1110 = Delay time in number of instruction cycles is 1,024 cycles
1101 = Delay time in number of instruction cycles is 896 cycles
1100 = Delay time in number of instruction cycles is 768 cycles
1011 = Delay time in number of instruction cycles is 640 cycles
1010 = Delay time in number of instruction cycles is 512 cycles
1001 = Delay time in number of instruction cycles is 384 cycles
1000 = Delay time in number of instruction cycles is 256 cycles
0111 = Delay time in number of instruction cycles is 128 cycles
0110 = Delay time in number of instruction cycles is 64 cycles
0101 = Delay time in number of instruction cycles is 32 cycles
0100 = Delay time in number of instruction cycles is 16 cycles
0011 = Delay time in number of instruction cycles is 8 cycles
0010 = Delay time in number of instruction cycles is 4 cycles
0001 = Delay time in number of instruction cycles is 2 cycles
0000 = Delay time in number of instruction cycles is 1 cycle
INTLVL<3:0>: Watermark Interrupt Enable bits
These bits specify the amount of remaining data yet to be transferred (transmitted and/or received)
upon which an interrupt is generated.
1111 = Amount of remaining data to be transferred is 576 bytes
1110 = Amount of remaining data to be transferred is 512 bytes
1101 = Amount of remaining data to be transferred is 448 bytes
1100 = Amount of remaining data to be transferred is 384 bytes
1011 = Amount of remaining data to be transferred is 320 bytes
1010 = Amount of remaining data to be transferred is 256 bytes
1001 = Amount of remaining data to be transferred is 192 bytes
1000 = Amount of remaining data to be transferred is 128 bytes
0111 = Amount of remaining data to be transferred is 67 bytes
0110 = Amount of remaining data to be transferred is 32 bytes
0101 = Amount of remaining data to be transferred is 16 bytes
0100 = Amount of remaining data to be transferred is 8 bytes
0011 = Amount of remaining data to be transferred is 4 bytes
0010 = Amount of remaining data to be transferred is 2 bytes
0001 = Amount of remaining data to be transferred is 1 byte
0000 = Transfer complete
For example, if DMACON2<3:0> = 0101(16 bytes remaining), the SSP2IF interrupt flag will
become set once DMABC reaches 00Fh. If user firmware then clears the SSP2IF interrupt flag, the flag
will not be set again by the hardware until after all bytes have been fully transmitted and the DMA
transaction is complete.
*/
|
And here is an example on how to use it
Code: |
// SPI
setup_spi2(SPI_MASTER | SPI_SCK_IDLE_HIGH | SPI_CLK_DIV_4 | SPI_XMIT_H_TO_L | SPI_SAMPLE_AT_END);
//DMA
setup_DMA(DMA_TXINC | DMA_RXINC | DMA_FULL_DUPLEX );
setup_DMA_int(DMA_DLYCYC_1 | DMA_INTLVL_0);
...
...
...
char txbuffer[128], rxbuffer[128];
DMA_transfer(128, txbuffer, rxbuffer);
|
|
|
|
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
|
Posted: Thu May 22, 2014 7:56 am |
|
|
Thanks Mr. zspikes.
I Suggest you change the version in the header to V1.1 and put your name as a contributtor/remaker(write changes history from version 1 to 1.1).
Thanks a lot. _________________ Eduardo Guilherme Brandt |
|
|
zspikes
Joined: 10 Jan 2013 Posts: 7
|
|
Posted: Fri May 23, 2014 10:57 am |
|
|
Dear friend,
You mean something like this?
Code: |
SPI DMA driver
File : spi_dma.c
Creator : Eduardo Guilherme Brandt
Contributor : Gerardo Daniel Cibeira
Version : v1.1
Contact : [email protected]
Historic : Version 1.0 - 31/01/2012 Eduardo Guilherme Brandt
Version 1.1 - 19/05/2014 Gerardo Daniel Cibeira
|
Also, a friend of mine wants to write an article in his blog http://www.micropic.es/mpblog/ about the SPI DMA module and the library you've made.
Do we have your permission to do this?
Thanks again! |
|
|
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
|
Posted: Fri May 23, 2014 11:06 am |
|
|
Yes, the header is very good!
Of course he has the permition! I´m very happy you´re using this file for something! It´s very good to contribute with something to this world. The life is short!
Good luck and have a nice weekend!
=) _________________ Eduardo Guilherme Brandt |
|
|
zspikes
Joined: 10 Jan 2013 Posts: 7
|
|
Posted: Fri May 23, 2014 11:48 am |
|
|
Great! Thanks a lot. Have a good weekend you too ;)
Bye! |
|
|
zspikes
Joined: 10 Jan 2013 Posts: 7
|
|
Posted: Tue Dec 16, 2014 10:38 am |
|
|
Hi!
I'm passing by to tell you I've just successfully tested the library in full duplex mode with interruptions :D
I'm using it to get readings via SPI from an ADC128S022. It's awesome, because while the CPU is busy processing the last sample, the DMA is getting the next sample, so I get a higher sample rate (it's for a robot I'm working on)
I'm using the following code:
setup:
Code: | setup_spi2(SPI_MASTER | SPI_CLK_DIV_4 | SPI_H_TO_L | SPI_XMIT_L_TO_H);
setup_DMA(DMA_TXINC | DMA_RXINC | DMA_FULL_DUPLEX | DMA_DLYINTEN);
setup_DMA_int(DMA_DLYCYC_1 | DMA_INTLVL_0); |
main code:
Code: |
//DMA buffers
int16 rxbuffer[8];
int16 txbuffer[8] = {0x0008,0x0010,0x0018,0x0020,0x0028,0x0030,0x0038,0x0000};
...
if(DMA_ended()){
//start next transaction
output_low(SPI_CS);
output_high(LEDS_ON);
DMA_transfer(16, txbuffer, rxbuffer);
}
|
interruption:
Code: | #INT_SSP2
void ssp2_isr(){
output_high(SPI_CS);
output_low(LEDS_ON);
} |
I'm very glad it's working. Thank you again Eduardo for shearing.
Bye! |
|
|
Eduardo__
Joined: 23 Nov 2011 Posts: 197 Location: Brazil
|
|
Posted: Mon Dec 22, 2014 10:05 am |
|
|
Trank you a lot for sharing your experience with us Mr. zspikes!!!
It´s very good to hear from you again!!!
I wish you a very Merry Xmas and a very good new year!!!!!!
Eduardo _________________ Eduardo Guilherme Brandt |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|