Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiling using macports arm-none-eabi-gcc v9.2.0_1 #1

Open
ddkn opened this issue Mar 18, 2021 · 6 comments
Open

Compiling using macports arm-none-eabi-gcc v9.2.0_1 #1

ddkn opened this issue Mar 18, 2021 · 6 comments

Comments

@ddkn
Copy link

ddkn commented Mar 18, 2021

Hello,

Thanks for the tutorial!

I was testing out the project and compiling using macports arm-none-eabi does not generate *.out files. In the Makefile the nano.specs seemed to be the offender. As the linker complained about not being able to find -lc_nano.

This solved my problem.

--- Makefile.orig	2021-03-18 15:21:20.000000000 -0300
+++ Makefile	2021-03-18 15:23:17.000000000 -0300
@@ -60,7 +60,7 @@
 
 LDFLAGS += -T$(LINKER_SCRIPT)
 LDFLAGS += -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard
-LDFLAGS += -specs=nano.specs -specs=nosys.specs -lc -lm -lnosys
+LDFLAGS += -specs=nosys.specs -lc -lm -lnosys
 LDFLAGS += -Wl,--gc-sections

Another issue was using an outdated GNU make. gmake v3.81 did not like the #define, where v4.3 worked as expected. FYI, I am on MacOS High Sierra. Otherwise I had to copy the contents of the define do-link into the build/%out: build/%.o section.

I was following your example trying to learn to use the DMA on top of Zephyr (avoiding their DMA+ADC drivers as custom options are needed for an ADC project. I could could get the DMA to initiate interrupts, but no data was ever copied from the peripheral to memory, as in your ex2.c.

I tried to simplify life by troubleshooting and just did straight memory to memory, but again, I see successful transmission interrupts occurring, but no data is ever copied from DMA2_Stream0->PAR to DMA2_Stream0->M0AR, whether it is a variable, array etc... Even if I initialize the destination array, it never changes, even though there was data in the source array or in ADC1->DR. Have you ever seen a situation where that occurs?

PS, thanks again for the nice tutorial!

@ian-ross
Copy link
Owner

I'm glad this stuff was useful for you!

Thanks for the information about the MacOS build. I'll try building with your change on Linux and if it works, I'll just remove nano.specs from the link line. I honestly can't remember why I ended up having it in there. I think it might have been a holdover from some debugging I was doing early on in the process. As for Make versions, I'd totally not thought about that. I use Arch Linux, which is a rolling update distribution, so things like Make are always on the latest version. I'll change that to get rid of the macro definition anyway, since I only use it in one place and I'm breaking my own "don't try to be clever with Make" rule there.

Finally, I'm interested in your DMA problem on Zephyr. I've only done limited unserious experimentation with Zephyr so far, so I can't answer your question. My usual approach to debugging this sort of thing is very very low-tech: run in the debugger, stop just before you trigger the DMA, print out the contents of every single register that might make a difference (DMA setup, peripheral setup, RCC stuff, interrupt setup) and sit down with the MCU reference manual and a cup of coffee and convince yourself that every bit is right. It's shockingly easy to misconfigure something, and it only takes one flag being wrong to mess things up. If that doesn't lead you to the answer, I'd find a working example, do the same "dump all the registers" thing right before a DMA is triggered and compare with what you've got. (I'm well aware that that sounds incredibly amateurish. I find debugging these things very hard, and the only way I've ever been able to do it is to get as much visibility into how the MCU is configured as possible. There's usually something that jumps out.)

My suspicion in this case would be that there is something getting set up by a Zephyr driver or part of the Zephyr BSP somewhere, and the state of the MCU doesn't correspond exactly to what you think it does.

@ddkn
Copy link
Author

ddkn commented Mar 18, 2021

Hi Ian!

Thanks for getting back to me. I was worried my board was bad, but compiling your code made me realize something is messed up on my side for sure. I was fighting with this all week, and a friend was helping a bit (when they have time) so I have been printing out registers and verify them (not amateurish at all, just convenient!). Since all I am doing at the moment is to get it to even transfer data, here is the code of what I have (if you care, haha),

As a heads up dma_adc_sample was just repurposed for memory-to-memory transfers as I was modifying code. Everything that is missing (and a basic infinite while loop) is the automagic from Zephyr, which is neat. It does have a DMA driver for the STM32 but, not continuous sampling of the ADC, so I figured not using the drivers and going manual was fine (or more likely to get working that deal with understanding their api), as I wanted the SDcard functionality convenience from the OS.

All the GPIO pins are enabled, as I am using the GPIO driver from Zephyr, but I was able to get your ex1.c working just fine, on top of their sample/basic/button project

#define MY_MAX_SIZE 10

static volatile uint16_t dma_adc_sample[MY_MAX_SIZE];
static volatile uint16_t test_src[MY_MAX_SIZE];

static volatile bool dma_complete = false;
static volatile bool dma_error = false;

static void DMA2_Stream0_IRQHandler(void *args)
{
›   printk("Entered DMA2 Interrupt\n");
›   if (DMA2->LISR & DMA_LISR_TCIF0) {
›   ›   DMA2->LIFCR |= DMA_LIFCR_CTCIF0;
›   ›   printk("Transfer complete\n");
›   ›   dma_complete = true;
›   }
›
›   if (DMA2->LISR & DMA_LISR_TEIF0) {
›   ›   DMA2->LIFCR |= DMA_LIFCR_CTEIF0;
›   ›   dma_error = true;
›   }
›   printk("test_src\tDMA+ADC\n");
›   for (int i = 0; i < MY_MAX_SIZE; i++) {
›   ›   printk("%x\t\t%x\n",
›   ›   ›   (uint32_t)test_src[i],
›   ›   ›   (uint32_t)dma_adc_sample[i]);
›   }
}

static inline void _dma_init()
{
›   /* Goal select DMA2 to use ADC1 on stream 0 channel 0 */

›   volatile uint32_t tmpreg;
›   /* Enable peripherial clock for DMA */
›   RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN;
›   /* Give 2 clock cycles to stabilize */
›   tmpreg = (RCC->AHB1ENR & RCC_AHB1ENR_DMA2EN);
›   (void)tmpreg;

›   /* Select Channel 0 for Stream 0 on DMA2
›    * On chip reset selects channel 0 by default
›    */
›   //DMA2_Stream0->CR = (0x0 << DMA_SxCR_CHSEL_Pos);

›   /* Configuration transfer */
›   /* Reset assumes periph. to memory, perih. no inc., DMA flow controller */
›   const uint32_t cr = (DMA_SxCR_MINC ›| /* Memory inc. */
›   ›   ›        DMA_SxCR_PINC ›|
›   ›   ›        DMA_SxCR_MSIZE_0 › | /* 16-bit */
›   ›   ›        DMA_SxCR_PSIZE_0 › | /* 16-bit */
›   ›   ›        DMA_SxCR_DIR_1 ›   | /* Mem to mem */
›   ›   ›        DMA_SxCR_PL_1);›     /* Priority high */

›   /* Populate source */
›   for (int i = 0; i < MY_MAX_SIZE; i++) {
›   ›   test_src[i] = i;
›   }
›
›   /* Specify transfer addresses and size for ADC and data */
›   DMA2_Stream0->PAR = (uint32_t)test_src;
›   DMA2_Stream0->M0AR = (uint32_t)dma_adc_sample;

›   /* Single byte transfer */
›   DMA2_Stream0->NDTR = sizeof(dma_adc_sample)/sizeof(uint16_t);

›   /* XXX Zephyr style IRQ */
›   IRQ_CONNECT(DMA2_Stream0_IRQn, PRIORITY_DMA,
›   ›       DMA2_Stream0_IRQHandler, 0, 0);
›   irq_enable(DMA2_Stream0_IRQn);

›   /* Enable transfer error+complete interrupts */
›   DMA2_Stream0->CR = (cr | DMA_SxCR_TCIE | DMA_SxCR_TEIE);

›   /* Enable transfers + Clear interrupt flags (datasheet suggestion) */
›   DMA2->LIFCR |= (DMA_LIFCR_CTCIF0 | DMA_LIFCR_CTEIF0 |
›   ›   ›   DMA_LIFCR_CTCIF1 | DMA_LIFCR_CTEIF1 |
›   ›   ›   DMA_LIFCR_CTCIF2 | DMA_LIFCR_CTEIF2 |
›   ›   ›   DMA_LIFCR_CTCIF3 | DMA_LIFCR_CTEIF3);
›   DMA2->HIFCR |= (DMA_HIFCR_CTCIF4 | DMA_HIFCR_CTEIF4 |
›   ›   ›   DMA_HIFCR_CTCIF5 | DMA_HIFCR_CTEIF5 |
›   ›   ›   DMA_HIFCR_CTCIF6 | DMA_HIFCR_CTEIF6 |
›   ›   ›   DMA_HIFCR_CTCIF7 | DMA_HIFCR_CTEIF7);

›   printk("DMA2_Stream0->FCR  : 0x%08x\n", DMA2_Stream0->FCR);
›   printk("DMA2_Stream0->NDTR : 0x%08x\n", DMA2_Stream0->NDTR);
›   printk("Starting DMA\n");
›   DMA2_Stream0->CR |= DMA_SxCR_EN;
}

With the output over the serial port given,

␀*** Booting Zephyr OS build zephyr-v2.5.0-965-g33c9be90ccea  ***
DMA2_Stream0->FCR  : 0x00000021
DMA2_Stream0->NDTR : 0x0000000a
Starting DMA
Entered DMA2 Interrupt
Transfer complete
test_src        DMA+ADC
0               0
1               0
2               0
3               0
4               0
5               0
6               0
7               0
8               0
9               0
Set up button at GPIOC pin 13
Set up LED at GPIOB pin 0
Press the button
RCC->CR            : 0x03077c80
RCC->CFGR          : 0x0000100a
RCC->PLLCFGR       : 0x23401204
RCC->AHB1ENR       : 0x005007ff
DMA2_Stream0->CR   : 0x00022e94
DMA2_Stream0->NDTR : 0x00000000
DMA2_Stream0->PAR  : 0x200204e0
DMA2_Stream0->MOAR : 0x200204cc
DMA2_Stream0->FCR  : 0x00000025
&dma_adc_sample[0] : 0x200204cc
dma_adc_sample     : 0x200204cc
test_src           : 0x200204e0
DMA transfer complete?

I am at a loss, as no one seems to have this issue, after days of googling. So I suspect it may be some permission issue with how zephyr is storing ram, and access to it, because otherwise I may need to look for another alternative.

PS. I used to do micros 10+ years ago, and things have clearly changed since then, haha. All the abstraction layers and libraries, so much more to debug.

PPS. I am also no expert in Zephyr, I just jumped in, haha. As I have a grad school experiment I am working on that needs a device to be isolated but measure off the ADC and store to an SD card. I naively thought the ADC modules supported continuous mode, but that is something they are working on. Ideally, having a cheap repairable/replaceable part is the priority, as it could get damaged easily, hence this direction.

@ddkn
Copy link
Author

ddkn commented Mar 19, 2021

Hey Ian,

So it was to do with the DCACHE, I posted this problem in Zephyr as well, but my friend had some time to help me tonight and found the solution was to use SCB_DisableDCache().

@ian-ross
Copy link
Owner

Ouch. I didn't know about that at all. I guess I just got lucky. I've been reading around a bit, and this comment seems to be about the clearest description of how to make DMA work properly with the data cache enabled (it's a general comment about doing DMA in the presence of caching and it makes total sense). I've also seen some stuff about DMA with some peripherals (in particular ETH) not working properly when the DCACHE is disabled, so it might be worth learning how to manage the cache invalidation properly anyway.

@ddkn
Copy link
Author

ddkn commented Mar 19, 2021

Yeah, seems like a common problem with many projects, such as ChibiOS and NuttX as well. I suppose it isn't common on many micros. Yeah I was a bit confused because I saw some that you enable DCache and ICache in enable_caches(void) in your common.c file. So perhaps using the CMSIS and STM32 provided files has some handling for that.

@ian-ross
Copy link
Owner

@ddkn Do you think you could try building the latest version of this? I've removed the reference to nano.specs and have removed that make macro, so hopefully it will just work on your setup now.

As for this DCACHE + DMA thing, I think I need to investigate that properly when I have time. I have another STM32 project where I'm using DMA to transmit data to a USART and I've not seen any problems, despite having the caches enabled and being totally slapdash about them! It's this thing (which is totally stalled at the moment, but I might get back to it later in the spring), and the relevant code that sets off a DMA transfer is here. I don't flush the data cache before that, but I've never noticed any problems with the data sent over the USART (it's USART3 on the F767 Nucleo board, which goes to the ST-Link virtual COM port for debugging, so I can see pretty easily if things get screwed up).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants