Autor Tema: [Aporte] Libreria SPI-DMA para PIC18 en CCS  (Leído 3548 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
[Aporte] Libreria SPI-DMA para PIC18 en CCS
« en: 22 de Mayo de 2014, 12:11:16 »
Hola amigos! Qué tal?
Estoy trabajando en un proyecto con un PIC18F46J50, en el cual necesito hacer transferencias de datos en bloques por SPI. Este micro posee un módulo DMA que trabaja en conjunto con el SPI, lo cual permite transferir grandes cantidades de información directamente a RAM, sin intervención del procesador.
En el foro de CCS encontré una librería hecha por un usuario. Le hice algunas modificaciones para que se parezca más a las funciones built-in de CCS y para optimizarla un poco. Además le agregué la función DMA_transfer() que hace transferencias fullduplex (envio y recepción simultáneos).

La comparto con ustedes en caso de que a alguien le sea útil. Y si alguien quiere contribuir con mejoras, bienvenido sea.
Funciona con todos los pics que posean SPI-DMA (PIC18F24J11, PIC18F46J11, PIC18F26J50, PIC18F46J50).

Código: C
  1. /*
  2.                           PIC18F24J11 DMA driver
  3.  
  4. File           :  spi_dma_PIC18F24J11.c
  5. Creator      :  Eduardo Guilherme Brandt
  6. Contributor :  Gerardo Daniel Cibeira                                
  7. Created     :  31/01/2012 ( V 1.0 )
  8. Contact     :  eduardogbrandt@yahoo.com.br
  9.  
  10. Historic    :  Version 1.0 - 31/01/2012 Eduardo Guilherme Brandt
  11.                Version 1.1 - 19/05/2014 Gerardo Daniel Cibeira
  12. */
  13.  
  14.  
  15. #include <dma.h>      //HEADER FILE
  16.  
  17.  
  18.  
  19. /*****************************************************************************************  
  20. *
  21. * DEFINED MACROS    
  22. *
  23. ******************************************************************************************/
  24.  
  25. #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.
  26. #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.
  27. #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.
  28.  
  29. #define  setup_DMA(x)        DMA_DMACON1 = x
  30. #define  setup_DMA_int(x)    DMA_DMACON2 = x
  31.  
  32. #define  DMA_start()           DMA_DMAEN_ = 1       //Start DMA transfer
  33. #define  DMA_is_busy()         DMA_DMAEN_           //DMA is working
  34. #define  DMA_ended()           !DMA_DMAEN_          //DMA transfer ended
  35. #define  DMA_SET_FULL_DUPLEX() DMA_DUPLEX1_ = 1; DMA_DUPLEX0_ = 0
  36. #define  DMA_SET_TX()          DMA_DUPLEX1_ = 0; DMA_DUPLEX0_ = 1
  37. #define  DMA_SET_RX()          DMA_DUPLEX1_ = 0; DMA_DUPLEX0_ = 0
  38.  
  39.  
  40.  
  41. /*****************************************************************************************
  42. *
  43. * DMA_write       : Write RAM data block using DMA
  44. * DMA_read        : Read RAM data block using DMA
  45. * DMA_transfer    : Does a fullduplex transfer using DMA
  46. *
  47. * Parameters:
  48. *
  49. *     buffer   :  pointer to data array for sending or receiving using DMA
  50. *     DataSize :  data size(number of bytes for writing or reading into "buffer" pointer)(Máx 1024 bytes)
  51. *
  52. ******************************************************************************************/
  53.  
  54. void DMA_write(int16 DataSize, char *buffer) {
  55.    if (DataSize>1024) DataSize=1024;
  56.    
  57.    DMA_SET_TX();
  58.    DMA_TXADDR(buffer);      
  59.    DMA_DMABC(DataSize-1);
  60.    DMA_start();
  61. }
  62.  
  63.  
  64. void DMA_read(int16 DataSize, char *buffer) {      
  65.    if (DataSize>1024) DataSize=1024;  
  66.    
  67.    DMA_SET_RX();
  68.    DMA_RXADDR(buffer);      
  69.    DMA_DMABC(DataSize-1);
  70.    DMA_start();
  71. }
  72.  
  73.  
  74. void DMA_transfer(int16 DataSize, char *txbuffer, char *rxbuffer) {        
  75.    if (DataSize>1024) DataSize=1024;
  76.    
  77.    DMA_SET_FULL_DUPLEX();
  78.    DMA_RXADDR(rxbuffer);
  79.    DMA_TXADDR(txbuffer);      
  80.    DMA_DMABC(DataSize-1);
  81.    DMA_start();
  82. }

Acá va el Header

Código: C
  1. /*
  2.                           PIC18F24J11 DMA driver
  3.  
  4. File           :  spi_dma_PIC18F24J11.h
  5. Creator      :  Eduardo Guilherme Brandt
  6. Contributor :  Gerardo Daniel Cibeira                    
  7. Created     :  31/01/2012 (v1.0)
  8. Contact     :  eduardogbrandt@yahoo.com.br
  9.  
  10. Historic    :  Version 1.0 - 31/01/2012 Eduardo Guilherme Brandt
  11.                Version 1.1 - 19/05/2014 Gerardo Daniel Cibeira
  12. */  
  13.  
  14. #ifndef SPI_DMA
  15. #define SPI_DMA
  16.  
  17. /***************************
  18. Further information
  19.  
  20. - I/O PIN CONSIDERATIONS
  21.    When enabled, the SPI DMA module uses the MSSP2 module. All SPI related input and output signals related
  22.    to MSSP2 are routed through the Peripheral Pin Select module.
  23.  
  24. - RAM TO RAM COPY OPERATIONS
  25.    Although the SPI DMA module is primarily intended to be used for SPI communication purposes, the module
  26.    can also be used to perform RAM to RAM copy operations.
  27.    To do this, configure the module for Full-Duplex Master mode operation, but assign the SDO2 output
  28.    and SDI2 input functions onto the same RPn pin in the PPS module. This will allow the module to operate in
  29.    Loopback mode, providing RAM copy capability.
  30.  
  31. - IDLE AND SLEEP CONSIDERATIONS
  32.    The SPI DMA module remains fully functional when the microcontroller is in Idle mode.
  33.    During normal sleep, the SPI DMA module is not functional and should not be used. To avoid corrupting a
  34.    transfer, user firmware should be careful to make certain that pending DMA operations are complete by
  35.    polling the DMAEN bit in the DMACON1 register prior to putting the microcontroller into Sleep.
  36.    
  37.    In SPI Slave modes, the MSSP2 module is capable of transmitting and/or receiving one byte of data while in
  38.    Sleep mode. This allows the SSP2IF flag in the PIR3 register to be used as a wake-up source. When the
  39.    DMAEN bit is cleared, the SPI DMA module is effectively disabled, and the MSSP2 module functions
  40.    normally, but without DMA capabilities. If the DMAEN bit is clear prior to entering Sleep, it is still possible to
  41.    use the SSP2IF as a wake-up source without any data loss.
  42.  
  43.    Neither MSSP2 nor the SPI DMA module will provide any functionality in Deep Sleep. Upon exiting from
  44.    Deep Sleep, all of the I/O pins, MSSP2 and SPI DMA related registers will need to be fully reinitialized before
  45.    the SPI DMA module can be used again.
  46. */
  47.  
  48. // Definitions for SPI DMA transfer
  49. #byte DMA_TXADDRH = 0x0F6A    //SPI DMA Tranmsit Data Pointer High Byte ---- 0000 73
  50. #byte DMA_TXADDRL = 0x0F6B    //SPI DMA Tranmsit Data Pointer Low Byte 0000 0000 73
  51. #byte DMA_RXADDRH = 0x0F68    //SPI DMA Receive Data Pointer High Byte ---- 0000 73
  52. #byte DMA_RXADDRL = 0x0F69    //SPI DMA Receive Data Pointer Low Byte 0000 0000 73
  53. #byte DMA_DMABCH  = 0x0F66    //SPI DMA Receive Data Pointer High Byte
  54. #byte DMA_DMABCL  = 0x0F67    //SPI DMA Byte Count Low Byte 0000 0000 73
  55.  
  56. // Definitions for SPI DMA transfer
  57. #byte DMA_DMACON1 = 0x0F88    //see DMACON1. DMA Control1 register options
  58. #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.                          
  59. #word DMA_TXADDR  = 0x0F6A    //**use DMA_TXADDR(x) for load data(byte reversed). SPI DMA Tranmsit Data Pointer(word)
  60. #word DMA_RXADDR  = 0x0F68    //**use DMA_RXADDR(x) for load data(byte reversed). SPI DMA Receive Data Pointer(word)
  61. #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)
  62.  
  63.  // DMACON1 bits
  64.  #bit DMA_SSCON1_    = DMA_DMACON1.7
  65.  #bit DMA_SSCON0_    = DMA_DMACON1.6                        
  66.  #bit DMA_TXINC_     = DMA_DMACON1.5
  67.  #bit DMA_RXINC_     = DMA_DMACON1.4
  68.  #bit DMA_DUPLEX1_   = DMA_DMACON1.3                          
  69.  #bit DMA_DUPLEX0_   = DMA_DMACON1.2
  70.  #bit DMA_DLYINTEN_  = DMA_DMACON1.1
  71.  #bit DMA_DMAEN_     = DMA_DMACON1.0
  72.  
  73. //setup_DMA() defines
  74. #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
  75. #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
  76. #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
  77. #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>
  78. #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>
  79. #define DMA_FULL_DUPLEX 0x08  //SPI DMA operates in Full-Duplex mode, data is simultaneously transmitted and received
  80. #define DMA_TX          0x04  //DMA operates in Half-Duplex mode, data is transmitted only
  81. #define DMA_RX          0x00  //DMA operates in Half-Duplex mode, data is transmitted only
  82. #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’
  83. #define DMA_DMAEN       0x01
  84.  
  85. //setup_DMA_int() defines
  86. #define DMA_DLYCYC_2048   0xF0
  87. #define DMA_DLYCYC_1024   0xE0
  88. #define DMA_DLYCYC_896    0xD0
  89. #define DMA_DLYCYC_768    0xC0
  90. #define DMA_DLYCYC_640    0xB0
  91. #define DMA_DLYCYC_512    0xA0
  92. #define DMA_DLYCYC_384    0x90
  93. #define DMA_DLYCYC_256    0x80
  94. #define DMA_DLYCYC_128    0x70
  95. #define DMA_DLYCYC_64     0x60
  96. #define DMA_DLYCYC_32     0x50
  97. #define DMA_DLYCYC_16     0x40
  98. #define DMA_DLYCYC_8      0x30
  99. #define DMA_DLYCYC_4      0x20
  100. #define DMA_DLYCYC_2      0x10
  101. #define DMA_DLYCYC_1      0x00
  102. #define DMA_INTLVL_576    0x0F
  103. #define DMA_INTLVL_512    0x0E
  104. #define DMA_INTLVL_448    0x0D
  105. #define DMA_INTLVL_384    0x0C
  106. #define DMA_INTLVL_320    0x0B
  107. #define DMA_INTLVL_256    0x0A
  108. #define DMA_INTLVL_192    0x09
  109. #define DMA_INTLVL_128    0x08
  110. #define DMA_INTLVL_67     0x07
  111. #define DMA_INTLVL_32     0x06
  112. #define DMA_INTLVL_16     0x05
  113. #define DMA_INTLVL_8      0x04
  114. #define DMA_INTLVL_4      0x03
  115. #define DMA_INTLVL_2      0x02
  116. #define DMA_INTLVL_1      0x01
  117. #define DMA_INTLVL_0      0x00
  118.  
  119.  
  120. /*
  121. In SPI Master mode, the DLYCYC<3:0> bits can be usedto control how much time the module will Idle between
  122. bytes in a transfer. By default, the hardware requires a minimum delay of: 8 TCY for FOSC/4, 9 TCY for FOSC/16
  123. and 15 TCY for FOSC/64. Additional delays can be added with the DLYCYC bits. In SPI Slave modes, the
  124. DLYCYC<3:0> bits may optionally be used to trigger an additional time-out based interrupt.
  125.  
  126. DMA_DLYCYCLES(bits 3 to 0):
  127. 1111 = Delay time in number of instruction cycles is 2,048 cycles
  128. 1110 = Delay time in number of instruction cycles is 1,024 cycles
  129. 1101 = Delay time in number of instruction cycles is 896 cycles
  130. 1100 = Delay time in number of instruction cycles is 768 cycles
  131. 1011 = Delay time in number of instruction cycles is 640 cycles
  132. 1010 = Delay time in number of instruction cycles is 512 cycles
  133. 1001 = Delay time in number of instruction cycles is 384 cycles
  134. 1000 = Delay time in number of instruction cycles is 256 cycles
  135. 0111 = Delay time in number of instruction cycles is 128 cycles
  136. 0110 = Delay time in number of instruction cycles is 64 cycles
  137. 0101 = Delay time in number of instruction cycles is 32 cycles
  138. 0100 = Delay time in number of instruction cycles is 16 cycles
  139. 0011 = Delay time in number of instruction cycles is 8 cycles
  140. 0010 = Delay time in number of instruction cycles is 4 cycles
  141. 0001 = Delay time in number of instruction cycles is 2 cycles
  142. 0000 = Delay time in number of instruction cycles is 1 cycle
  143.  
  144.  
  145.  
  146. INTLVL<3:0>: Watermark Interrupt Enable bits
  147. These bits specify the amount of remaining data yet to be transferred (transmitted and/or received)
  148. upon which an interrupt is generated.
  149. 1111 = Amount of remaining data to be transferred is 576 bytes
  150. 1110 = Amount of remaining data to be transferred is 512 bytes
  151. 1101 = Amount of remaining data to be transferred is 448 bytes
  152. 1100 = Amount of remaining data to be transferred is 384 bytes
  153. 1011 = Amount of remaining data to be transferred is 320 bytes
  154. 1010 = Amount of remaining data to be transferred is 256 bytes
  155. 1001 = Amount of remaining data to be transferred is 192 bytes
  156. 1000 = Amount of remaining data to be transferred is 128 bytes
  157. 0111 = Amount of remaining data to be transferred is 67 bytes
  158. 0110 = Amount of remaining data to be transferred is 32 bytes
  159. 0101 = Amount of remaining data to be transferred is 16 bytes
  160. 0100 = Amount of remaining data to be transferred is 8 bytes
  161. 0011 = Amount of remaining data to be transferred is 4 bytes
  162. 0010 = Amount of remaining data to be transferred is 2 bytes
  163. 0001 = Amount of remaining data to be transferred is 1 byte
  164. 0000 = Transfer complete
  165.  
  166. For example, if DMACON2<3:0> = 0101(16 bytes remaining), the SSP2IF interrupt flag will
  167. become set once DMABC reaches 00Fh. If user firmware then clears the SSP2IF interrupt flag, the flag
  168. will not be set again by the hardware until after all bytes have been fully transmitted and the DMA
  169. transaction is complete.
  170. */

Acá va un ejemplo de configuración del módulo para trabajar en moodo fullduplex

Código: C
  1. // SPI
  2. setup_spi2(SPI_MASTER | SPI_SCK_IDLE_HIGH | SPI_CLK_DIV_4 | SPI_XMIT_H_TO_L | SPI_SAMPLE_AT_END);
  3.    
  4. //DMA
  5. setup_DMA(DMA_TXINC | DMA_RXINC | DMA_FULL_DUPLEX );
  6. setup_DMA_int(DMA_DLYCYC_1 | DMA_INTLVL_0);
  7. ...
  8. ...
  9. ...
  10. char txbuffer[128], rxbuffer[128];
  11. DMA_transfer(128, txbuffer, rxbuffer);

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
Re: [Aporte] Libreria SPI-DMA para PIC18 en CCS
« Respuesta #1 en: 22 de Mayo de 2014, 15:06:29 »
Ya tiene el CCS su librería para usar DMA...
Menudo trabajo te has tomado... ((:-)) ((:-))
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
Re: [Aporte] Libreria SPI-DMA para PIC18 en CCS
« Respuesta #2 en: 22 de Mayo de 2014, 16:49:01 »
Qué versión? Porque estuve buscando y no encontré nada :shock: Ojo que no es el mismo modulo DMA que traen los dsPIC. Este solo funciona con el modulo SPI de algunos PIC18.
Saludos!

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
Re: [Aporte] Libreria SPI-DMA para PIC18 en CCS
« Respuesta #3 en: 22 de Mayo de 2014, 17:09:35 »
Si, me refería al DSPIC, esta en el manual del compilador, ultima versión...
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: [Aporte] Libreria SPI-DMA para PIC18 en CCS
« Respuesta #4 en: 23 de Mayo de 2014, 02:07:27 »
¡Está genial, muchas gracias por el aporte Gera!

Desconectado gera

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2188
Re: [Aporte] Libreria SPI-DMA para PIC18 en CCS
« Respuesta #5 en: 23 de Mayo de 2014, 09:42:28 »
Si, me refería al DSPIC, esta en el manual del compilador, ultima versión...

Ah sí, pero este es diferente. Me acabo de fijar en el manual del CCS v5 y en el .h del PIC18F46J50 y efectivamente no soporta este módulo.
Quería hacer un instructivo/tutorial ampliando un poco más, pero disponía de poco tiempo. Probablemente cuando tenga un rato lo haga ;)

¡Está genial, muchas gracias por el aporte Gera!

Me alegro que te guste Manolo!

Saludos!

"conozco dos cosas infinitas: el universo y la estupidez humana. Y no estoy muy seguro del primero." A.Einstein

Desconectado MGLSOFT

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 7918
Re: [Aporte] Libreria SPI-DMA para PIC18 en CCS
« Respuesta #6 en: 23 de Mayo de 2014, 09:45:38 »
Tenes razón Gera!!
Es muy bueno tu aporte, gracias!! ((:-)) ((:-))
Todos los dias aprendo algo nuevo, el ultimo día de mi vida aprenderé a morir....
Mi Abuelo.