EEVblog Electronics Community Forum

Electronics => Microcontrollers => Topic started by: luiHS on August 18, 2018, 04:43:46 am

Title: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 04:43:46 am
I'm starting to use DMA, and I'm porting an application from Kinetis MK66 to NXP RT1020, and from STM32 to RT1020.

As I still did not know how the DMA works, to copy memory data to GPIO ports, I routed a couple of boards without taking into account the order of the ports.

To read data by DMA using SPI, I see no problems. The problem, I think it comes when I'm going to use DMA memory to peripherals (seven GPIO ports).

From what I read, it seemed to me that I understand that the addresses of the ports to which I am going to copy from memory using the DMA, should have consecutive  addresses, could not use ports that do not have consecutive addresses.

Is this so, or can it be fixed by software, if I have not routed the ports with consecutives addresses ?

On one of the boards, I can fix it easily, soldering some cables, to the ports that I do not use, and for the other ports I would make a small board that reorders them, to connect them all to an IDC connector of 2x16, to which they connect to LED panels HUB75 of my application.

With the other board, I have it more complicated, because it is the evaluation board of the RT1020, and on this board there are very few accessible ports. Only the ports just for my application, but of all these, once discarded those using the SPI that I need also, I would not have any group of 7 consecutive ports. I would only have 5 consecutive ports, and the other 2 I would have to wire them, desoldering a pair of very small resistors (0402 or 0201), to weld there 2 wires.

Is any software solution possible, to be able to use 7 non-contiguous ports in their addresses, to use DMA memory to peripheral?

Greetings.

Title: Re: DMA, memory to peripheral
Post by: ataradov on August 18, 2018, 04:52:36 am
Usually GPIO ports are not really compatible with DMA unless hardware has some additional magic to handle it.

DMA also needs a beat trigger, which in case of an SPI peripheral is a shift register empty flag. You can probably use a timer for that, but again it depends on the DMA controller and if it can do this. Otherwise DMA will just instantly go through all the values.

What sort of data you are planning to write?
Title: Re: DMA, memory to peripheral
Post by: andyturk on August 18, 2018, 06:23:45 am
I implemented a parallel SPI tranceiver once on STM32 using a timer and a 16-bit GPIO port. There were two tricky parts: 1) getting the timer to stop after a certain number of frames, and 2) "transposing" the bits back into words (and vice versa). But it worked out well and was a nice way to read a bunch of outboard ADCs that shared the same clock.

I don't understand the OP's desire for "consecutive addresses" though. Most DMA controllers allow you to increment one of the two pointers by zero, so you keep transferring to or from the same address (which is typically a peripheral register). And even if the port peripherals are somehow "consecutive", the data registers almost certainly won't be.

If you had to DMA to/from locations that were arbitrarily scattered in memory, you could probably do it with linked DMA transfers (if the chip supports that).
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 06:40:58 am
Usually GPIO ports are not really compatible with DMA unless hardware has some additional magic to handle it.

DMA also needs a beat trigger, which in case of an SPI peripheral is a shift register empty flag. You can probably use a timer for that, but again it depends on the DMA controller and if it can do this. Otherwise DMA will just instantly go through all the values.

What sort of data you are planning to write?

Yes, there is no problem in that issue, I have always an external trigger signal to load buffer of DMA, for Memory to Peripheral and also an external trigger signal to Read by SPI using DMA.

My problem is with the DMA, from Memory to Peripherals (seven GPIO ports), if all those ports must be in consecutive directions for it to work. I already routed the board, and those seven ports were not in consecutive directions (I did not know at that time). I do not know if that can be fixed by software, or I must do it by hardware, rewiring the board for the tests, and routing again for the final product.

Title: Re: DMA, memory to peripheral
Post by: ataradov on August 18, 2018, 06:44:05 am
I'm assuming you are talking about consecutive pins in a port? Even then, I don't see how DMA will do anything here. Typically GPIO pins are controlled by individual bits in a register, so DMA will not help.

Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 06:56:05 am
I implemented a parallel SPI tranceiver once on STM32 using a timer and a 16-bit GPIO port. There were two tricky parts: 1) getting the timer to stop after a certain number of frames, and 2) "transposing" the bits back into words (and vice versa). But it worked out well and was a nice way to read a bunch of outboard ADCs that shared the same clock.

I don't understand the OP's desire for "consecutive addresses" though. Most DMA controllers allow you to increment one of the two pointers by zero, so you keep transferring to or from the same address (which is typically a peripheral register). And even if the port peripherals are somehow "consecutive", the data registers almost certainly won't be.

If you had to DMA to/from locations that were arbitrarily scattered in memory, you could probably do it with linked DMA transfers (if the chip supports that).


Maybe I did not explain myself well, or I still do not understand how the DMA works.

It is about reading seven GPIO ports and dumping the read into an array, so that with each reading, it is saved in seven elements of the array.

From what I have read, when configuring the DMA, we define the address of origin, destination address and width of the data to be transferred, also if we want to increase the address of origin or destination with each reading.

The entry addresses (GPIO ports) are always the same, only the destination varies, which will increase by seven with each reading.

If in the DMA, I configure the source address (I suppose the address of the first GPIO port), and the width of the data to be read (seven ports), I suppose that the addresses of the seven ports to be read must be consecutive, not I can take any group of seven ports, but these have to have their addresses one after the previous one.

For example, in the RT1020, those seven GPIO ports to read by DMA, I understand that these could be:

GPIO_AD_B1_01
GPIO_AD_B1_02
GPIO_AD_B1_03
GPIO_AD_B1_04
GPIO_AD_B1_05
GPIO_AD_B1_06
GPIO_AD_B1_07

but I could not use this port configuration, because their addresses are not contiguous:

GPIO_SD_B1_03
GPIO_AD_B0_01
GPIO_SD_B0_04
GPIO_AD_B1_01
GPIO_AD_B0_07
GPIO_SD_B1_02
GPIO_SD_B0_03
Title: Re: DMA, memory to peripheral
Post by: ataradov on August 18, 2018, 07:02:36 am
What makes you think that DMA can do this with GPIO ports? There are no 7 ports, there are 7 bits in the same register.

You can read from GPIO pad status register (PSR) using DMA, but I don't see how this is helpful.

What is your actual goal here?
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 07:03:18 am
I'm assuming you are talking about consecutive pins in a port? Even then, I don't see how DMA will do anything here. Typically GPIO pins are controlled by individual bits in a register, so DMA will not help.

There is a trigger signal generated with a timer for the DMA to send the data, from memory to ports, with each pulse of that signal.

And when it comes to reading data, then there is an external trigger signal for the DMA to start capturing.

My problem is not that, but the configuration of the ports to send signals using DMA, from memory to peripherals. If those ports must have configuous addresses for it to work.
Title: Re: DMA, memory to peripheral
Post by: ataradov on August 18, 2018, 07:07:49 am
Not only they need to be sequential, they need to be 0-7 or 8-15 or 16-23, or 24-31. And you also need to check that GPIO handles byte writes correctly.

And you won't get 7 elements in the memory, you will get one byte per sample in which bits represent states of the corresponding pins.

GPIO is not designed to work with DMA.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 07:11:08 am
What makes you think that DMA can do this with GPIO ports? There are no 7 ports, there are 7 bits in the same register.

You can read from GPIO pad status register (PSR) using DMA, but I don't see how this is helpful.

What is your actual goal here?

Read from an array (memory) and copy the data to seven GPIO ports (peripheral), using DMA. The trigger for DMA is generated by a timer.

Each pulse of the timer, the DMA must copy seven elements of the array to the seven GPIO ports, then increase the address of the array to copy the next seven elements of the array with the next pulse of the timer.

It is Memory to Peripheral transfer, using DMA, with increasing address of origin. It is working with STM32 and Kinetis MK66, now I need to port it to RT1020.
Title: Re: DMA, memory to peripheral
Post by: ataradov on August 18, 2018, 07:15:45 am
Read from an array (memory) and copy the data to seven GPIO ports (peripheral), using DMA. The trigger for DMA is generated by a timer.
There are no 7 GPIO ports. There are 7 bits in the port register. They are not the same thing.


It is working with STM32 and Kinetis MK66, now I need to port it to RT1020.
Can you show relevant code? I don't see how that is possible. What is the destination address set in the DMA?

It is probably possible using bit-banding, but it does not look like RT1020 has it.
Title: Re: DMA, memory to peripheral
Post by: legacy on August 18, 2018, 09:26:49 am
what is the purpose of that?
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 09:55:18 am
Read from an array (memory) and copy the data to seven GPIO ports (peripheral), using DMA. The trigger for DMA is generated by a timer.
There are no 7 GPIO ports. There are 7 bits in the port register. They are not the same thing.

Ok, I think I'm starting to understand. Then, when I configure DMA, I put in the source address the address of the first GPIO pin of the port to read and in the transfer source address width the number of bits to read, then when the DMA reads, each GPIO pin is a one bit of a byte.

But I must always configure the Source Address with the address of the first GPIO pin and how many bits to read, and all GPIOs must be contiguous in the same port starting from the indicated address. . This is so??.  I have check source code of one example and open the function to prepare the DMA, here I can see all the parameters to configure it.

In the SDK there are no examples of Memory to Peripheral or Peripheral to Memory. But I suppose that really a GPIO has an address assigned to it, and therefore it must be the same if in an example of Memory to Memory, I assigns to the address of origin or destination, the address of a GPIO port. I'm right ?.


* This function prepares the transfer configuration structure according to the user input.
 *
 * @param config The user configuration structure of type edma_transfer_t.
 * @param srcAddr eDMA transfer source address.
 * @param srcWidth eDMA transfer source address width (bytes).
 * @param destAddr eDMA transfer destination address.
 * @param destWidth eDMA transfer destination address width (bytes).
 * @param bytesEachRequest eDMA transfer bytes per channel request.
 * @param transferBytes eDMA transfer bytes to be transferred.
 * @param type eDMA transfer type.
 * @note The data address and the width data must be consistent. For example, if the SRC
 * is 4 bytes, the source address must be 4 bytes aligned, or it results in
 * source address error (SAE).
 * /
void EDMA_PrepareTransfer (edma_transfer_config_t * config,
                          void * srcAddr,
                          uint32_t srcWidth,
                          void * destAddr,
                          uint32_t destWidth,
                          uint32_t bytesEachRequest,
                          uint32_t transferBytes,
                          edma_transfer_type_t type);
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 09:59:23 am
what is the purpose of that?

Play animations in HUB75 LED panels.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 10:01:51 am
It is working with STM32 and Kinetis MK66, now I need to port it to RT1020.
Quote
Can you show relevant code? I don't see how that is possible. What is the destination address set in the DMA?

It is probably possible using bit-banding, but it does not look like RT1020 has it.


This is with STM32, Memory to Peripheral. The memory is an array, Peripheral is 6 x GPIO in port D. The size of the data is one byte, although really it only copy to 6 x GPIO (I mean 6 bits), I still do not understand this detail. This prepares the DMA to transfer 256 bits of an Array to 6 x GPIO in port D, using a timer as trigger for DMA transfer.


   GPIO_InitStruct.GPIO_Pin =  GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6;
   GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
   GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
   GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;

   GPIO_Init(GPIOD, &GPIO_InitStruct);

   // DMA init (DMA2, Channel6, Stream5)
   DMA_Cmd(DMA2_Stream5, DISABLE);
   DMA_DeInit(DMA2_Stream5);
   DMA_InitStructure.DMA_Channel = DMA_Channel_6;
   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOD->ODR;
   DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;
   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
   DMA_InitStructure.DMA_BufferSize = 256;
   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 8bit
   DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
   DMA_Init(DMA2_Stream5, &DMA_InitStructure);

Title: Re: DMA, memory to peripheral
Post by: andersm on August 18, 2018, 10:52:59 am
The memory is an array, Peripheral is 6 x GPIO in port D. The size of the data is one byte, although really it only copy to 6 x GPIO (I mean 6 bits), I still do not understand this detail.
Your example code initializes 7 pins of GPIOD. Anyway, on each DMA transfer cycle, one byte will be written into GPIOD->ODR. The effect is the same as if you had written the value to the register in code, all pins that have been configured as outputs will change state according to the written value. But a full byte will be written each transfer cycle.

Mike Harrison did a video on using GPIO DMA to bitbang SPI that may or may not be helpful: https://www.youtube.com/watch?v=XlKilhcP_ic (https://www.youtube.com/watch?v=XlKilhcP_ic)

Quote
This prepares the DMA to transfer 256 bits of an Array to 6 x GPIO in port D
Bytes. The array does contain 256 bits for each pin, but the transfer is done in bytes.

Quote
Code: [Select]
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;
This field should be initialized with the address of the source memory array.

Also, as a sidenote, not all STM32s have identical DMA controllers. It might be useful to say which specific chip the code you're trying to port was written for.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 18, 2018, 11:44:31 am
Thanks for your help andersm.

I have been looking in some sources of the RT1020 SDK, to see if I found out the difference between Memory to Memory and Memory to Periphal or Periphal to Memory, since I understand that a peripheral is also assigned a memory address.

This is what I have found, it seems that the only thing different is an offset (widht of source and destiny) that is applied to source and destiny when there is a Memory to Memory transfer. I still do not understand what this offset consists of.

    switch (type)
    {
        case kEDMA_MemoryToMemory:
            config->destOffset = destWidth;
            config->srcOffset = srcWidth;
            break;
        case kEDMA_MemoryToPeripheral:
            config->destOffset = 0U;
            config->srcOffset = srcWidth;
            break;
        case kEDMA_PeripheralToMemory:
            config->destOffset = destWidth;
            config->srcOffset = 0U;
            break;
        default:
            break;
    }
Title: Re: DMA, memory to peripheral
Post by: ataradov on August 18, 2018, 04:24:26 pm
I put in the source address the address of the first GPIO pin of the port to read and in the transfer source address width the number of bits to read, then when the DMA reads, each GPIO pin is a one bit of a byte.
Correct, except the you specify the addres of a register containing all pins, not a specific pin. And size granularity is 8-bit.

But I must always configure the Source Address with the address of the first GPIO pin and how many bits to read, and all GPIOs must be contiguous in the same port starting from the indicated address. . This is so??
Yes, and not only contiguous, but in the ranges I specified.

In the SDK there are no examples of Memory to Peripheral or Peripheral to Memory. But I suppose that really a GPIO has an address assigned to it, and therefore it must be the same if in an example of Memory to Memory, I assigns to the address of origin or destination, the address of a GPIO port. I'm right ?.
Correct. In this case you need to specify the address of the GPIO data register (DR) of the corresponding port: "DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOD->DR;" (substitute GPIOD with whatever port you want).
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 19, 2018, 12:16:42 am
 
Ok, thanks ataradov.

Little by little, I understand how the DMA works, and how it is configured, at first I found something quite complex and little documented (this last I still think).

Then to transfer from or to GPIO ports, I must indicate the port address, so the address is per port, not per pin. For example, a port D has an address, and by indicating the width of the transfer to 1byte or 2 bytes, the status of GPIOs 0 to 7, or 0 to 15, is transferred. Is this correct?
Then it could not be read or transferred by DMA, for example, port D, GPIO 3 to 10, it always has to be from 0 and in bytes?.

About the Memory to Peripheral or Peripheral to Memory, with respect to the Memory to Memory transfer; Besides that when a Peripheral is involved, only the width of the data is indicated in the Memory (origin or destination), and not in the Peripheral, is there any other difference?

    switch (type)
    {
        case kEDMA_MemoryToMemory:
            config->destOffset = destWidth;
            config->srcOffset = srcWidth;
            break;
        case kEDMA_MemoryToPeripheral:
            config->destOffset = 0U;
            config->srcOffset = srcWidth;
            break;
        case kEDMA_PeripheralToMemory:
            config->destOffset = destWidth;
            config->srcOffset = 0U;
            break;
        default:
            break;
    }


In this example of a source that I found, I do not understand why the address of the Memory (which is an array) in a Memory to Peripheral transfer is set to zero. Should not this address be the address of the array to be transmitted?

  // DMA init (DMA2, Channel6, Stream5)
   DMA_Cmd(DMA2_Stream5, DISABLE);
   DMA_DeInit(DMA2_Stream5);
   DMA_InitStructure.DMA_Channel = DMA_Channel_6;
   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&GPIOD->ODR;
   DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;
   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
   DMA_InitStructure.DMA_BufferSize = 256;
   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 8bit
   DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_Byte;
   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
   DMA_Init(DMA2_Stream5, &DMA_InitStructure);

Title: Re: DMA, memory to peripheral
Post by: luiHS on August 19, 2018, 12:18:22 am

Quote
Code: [Select]
    DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)0;
This field should be initialized with the address of the source memory array.

Also, as a sidenote, not all STM32s have identical DMA controllers. It might be useful to say which specific chip the code you're trying to port was written for.

And why in this example its set to zero ?. I do not understand it. Should not this address be the address of the array to be transmitted?.

This is the source code for STM32F405, STM32F407, and I want to port it to NXP RT1020. Although really, it is not about porting the original source of STM32 to RT1020, but understanding how it works to be able to write my own code for RT1020.

Title: Re: DMA, memory to peripheral
Post by: ataradov on August 19, 2018, 12:21:37 am
Then to transfer from or to GPIO ports, you must indicate the port address, so the address is per port, not per pin. For example, a port D has an address, and by indicating the width of the transfer to 1byte or 2 bytes, the status of GPIOs 0 to 7, or 0 to 15, is transferred. Is this correct?
Correct.

Then it could not be read or transferred by DMA, for example, from port D, from ports GPIO 3 to 10, it always has to be from 0 and in bytes?.
Yep. And for writes it is not inherently  guaranteed that you can do byte-sized writes. That totally depends on specific hardware implementation. It is very much possible that entire words has to be written or results may be undefined. It does not look like this is explicitly documented anywhere though.

In this example of a source that I found, I do not understand why the address of the Memory (which is an array) in a Memory to Peripheral transfer is set to zero. Should not this address be the address of the array to be transmitted?
I don't know the specifics of that library and the device to answer this.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 19, 2018, 12:37:17 am
In this example of a source that I found, I do not understand why the address of the Memory (which is an array) in a Memory to Peripheral transfer is set to zero. Should not this address be the address of the array to be transmitted?
I don't know the specifics of that library and the device to answer this.


OK, I found this in the source code, it seems that the source address of the array is loaded later, every time the DMA transfer is triggered.  So it seems that it is an address that is different, in this case, each time a transfer is made.

         DMA2_Stream5->M0AR = (uint32_t)(rgbbuf + ((rgbrow * 256) + (rgbsubframe * targetSubframeSize)));
         DMA2->LIFCR = 0b111101;
         DMA2_Stream5->CR |= DMA_SxCR_EN;


I looked in the code "M0AR" and found this:

         typedef struct
         {
           __IO uint32_t CR;     /*!< DMA stream x configuration register      */
           __IO uint32_t NDTR;   /*!< DMA stream x number of data register     */
           __IO uint32_t PAR;    /*!< DMA stream x peripheral address register */
           __IO uint32_t M0AR;   /*!< DMA stream x memory 0 address register   */
           __IO uint32_t M1AR;   /*!< DMA stream x memory 1 address register   */
           __IO uint32_t FCR;    /*!< DMA stream x FIFO control register       */
         } DMA_Stream_TypeDef;

         typedef struct
         {
           __IO uint32_t LISR;   /*!< DMA low interrupt status register,      Address offset: 0x00 */
           __IO uint32_t HISR;   /*!< DMA high interrupt status register,     Address offset: 0x04 */
           __IO uint32_t LIFCR;  /*!< DMA low interrupt flag clear register,  Address offset: 0x08 */
           __IO uint32_t HIFCR;  /*!< DMA high interrupt flag clear register, Address offset: 0x0C */
         } DMA_TypeDef;
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 19, 2018, 05:20:06 am
I checked the Memory Map in the Reference Manual and I'm confused.
There are four ports, GPIO1, GPIO2, GPIO3 and GPIO5 (there is no GPIO4). GPIO1 to GPIO3, each one with 32 IO pins, and GPIO5 only with 3 IO pins.

If I want to send data to 7 x IO ports per DMA, does this mean that I can only use the first seven IO pins of each GPIO1, GPIO2 or GPIO3 port?

For each GPIO, the pins are GPIOn_IO00 to GPIOn_IO31, where n is 1 to 3.

Therefore, it is not possible to send data, for example port GPIO1_I008 to GPIO1_I015.
Can I only send data to these ?, If I have understand correctly.

GPIO1_I000 to GPIO1_I007  ---> 1 byte
GPIO1_I000 to GPIO1_I015  ---> 2 bytes
GPIO1_I000 to GPIO1_I023  ---> 3 bytes
GPIO1_I000 to GPIO1_I031  ---> 4 bytes

The problem is that some of the ports are used in my circuit, so it is not possible to send data to more than 8 IO ports if I connect my 7 pins to the 2nd, 3rd or 4th byte of the corresponding GPIO.
Title: Re: DMA, memory to peripheral
Post by: ataradov on August 19, 2018, 05:25:29 am
Therefore, it is not possible to send data, for example port GPIO1_I008 to GPIO1_I015.
Can I only send data to these ?, If I have understand correctly.
No, you can write a byte at address GPIO1 + 1.

In the code it will be something like this: "(uint8_t *)&GPIOD->ODR + 1"; Or just manually specify the address: 0x401b8001 for GPIO0 byte 1.

+1 can be +0, +1, +2 and +3 to get access to bits 0-7, 8-15, 16-23, and 24-31. Again, you will have to verify that GPIO peripheral handles byte writes at any offset  within a word correctly.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 19, 2018, 05:39:29 am

OK thanks ataradov, I will check.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 19, 2018, 07:13:15 am
 
I reviewed the Data Sheet and the Reference Manual to identify the available GPIO for RT1020 LQFP100, which is the current available, so with fewer GPIO ports than the LQFP144.

I see some strange thoughts, some IO ports are not available, but the problem is that they are not contiguous.

I attach images of the assignment of GPIO1, GPIO2 and GPIO3. Those that I have marked in red, are not available in the LQFP100. I see that for each GPIO there are only 16 available ports, that is 2 bytes, but they are not contiguous, there are gaps between them.

For example for GPIO1, the first available port is GPIO1_6 (instead of GPIO1_0), then it continues until 15, and there is a gap without ports until 26.

The question is that if I connect, for example, the first 8 ports available in GPIO1 by DMA, these are considered the 1st byte, and the next 8 ports would be the second byte?

Byte 1
GPIO1_6
GPIO1_7
GPIO1_8
GPIO1_9
GPIO1_10
GPIO1_11
GPIO1_12
GPIO1_13

Byte 2
GPIO1_14
GPIO1_15
GPIO1_26
GPIO1_27
GPIO1_28
GPIO1_29
GPIO1_30
GPIO1_31
Title: Re: DMA, memory to peripheral
Post by: ataradov on August 19, 2018, 05:16:08 pm
The question is that if I connect, for example, the first 8 ports available in GPIO1 by DMA, these are considered the 1st byte, and the next 8 ports would be the second byte?
DMA controller won't be able to do anything with this.

You need to evaluate if Smart External Memory Controller (SEMC) will work for you. I still don't see the full picture of what you are doing, but it sounds like "8080 display frame buffer" mode is what you need.
Title: Re: DMA, memory to peripheral
Post by: Siwastaja on August 20, 2018, 02:47:37 pm
You need to get your basic terminology right before you have any chance understanding the documentation.

A PORT is the collection of the bits.

You don't have "first 8 ports available in GPIO1".

GPIO1 is the port.
Title: Re: DMA, memory to peripheral
Post by: luiHS on August 20, 2018, 07:10:23 pm
You need to get your basic terminology right before you have any chance understanding the documentation.

A PORT is the collection of the bits.

You don't have "first 8 ports available in GPIO1".

GPIO1 is the port.

I understand the concept, it is only a question of nomenclature when expressing it. A port is, for example, GPIO1, and each pin is a bit of the port, so if there are 16 input/output pins in GPIO1, each one is a bit of the port and I can read or write by DMA one or several bytes, not necessarily from the first byte, but always full bytes.

My question was about the grouping and order of the bits, in this particular case, since on the Reference Manual and the Datasheet, in the ports there are gaps between bits (for LQFP100), they are not contiguous (in appearance). Probably, internally, all these bits are contiguous , and it is not a problem, in fact when counting them I see that there are 16 bits per port, that is 2 bytes, instead of the 4 bytes that should be for the LQFP144. I will do tests, and I will check with the oscilloscope to corroborate what I suspect (internally all those bits are contiguous, although in the manual there seem to be gaps between them)

Knowing that, and that I can read or write in one of those bytes, although it is not the first one, I'm already clear about it. In my hardware, for the tests, I will have to reorder the routing of the pins of each port, to always catch bits that are part of the same port byte. At first I mixed bits of several ports and without order, for lack of information, I thought that each pin could be treated individually.

Now I am with the tests, but I am already understanding the concepts necessary to handle the DMA, especially with parallel read / write, to or from the GPIO ports. I still have to check how to configure automatically to increase the address of origin or detiny and how the circular buffer works, I have the concepts, but I lack the practice to be able to configure everything.