This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

DMA doesn't work in Keil, but it works in Atmel Studio

Hello to all,
I' using Keil MDK ARM IDE to work on a a project with an ATSAML21E18B connected to a shift register. I want to use DMA to send data through SCLK and MOSI pins. To configure my project i used the AtmelStart online platform.
I connected the SPI pins to a digital signal analyzer and I program/debugg it with the Segger J-Link.
The test program I'm working on is simple:
1- init the hardware
2- fill an array with fixed value
3- send it using DMA
4- a callback function blinks a LED when DMA has finished the data sending
5- loop 2,3,4 forever

Everything seems correct, instead it doesn't work: using Keil ARM 5.29 my code compiles (compilation without optimizations) then runs, it seems to set up all hardware devices correctly, but when my code calls the "spi_m_dma_transfer(...)" function (line 65) nothing flows out from SPI pins, and the DMA callback is never called.
I couldn't understand where the problem was until I tried to compile the exact same project with AtmelStudio: it worked!
I setted up a Keil project in the same folder with the AtmelStudio project: compiling with keil does not work, compiling with AtmelStudio works.

After two week of sleepless nights I can't understand how the same code could work differently using two IDEs and I don't know which test can still be done.
I attach here the project (Keil and AtmelStudio project) and I hope some of you can help me.
Thanks!

/* Transfer completed callback */
static void vUtil_DMA_transfer_SPI_LED( struct _dma_resource *resource ) {
	while( hri_sercomspi_get_INTFLAG_TXC_bit( SERCOM0 ) == 0 );					// wait for the last bit is sent

	gpio_set_pin_level( STAT_LED, true );												// turn ON the status LED
	delay_short();																				// wait
	gpio_set_pin_level( STAT_LED, false );												// turn OFF the status LED
	delay_short();																				// wait
}

int main( void ) {
	init_mcu();																					// system_init
	// SPI_LED_CLOCK_init
	hri_gclk_write_PCHCTRL_reg( GCLK, SERCOM0_GCLK_ID_CORE, CONF_GCLK_SERCOM0_CORE_SRC | ( 1 << GCLK_PCHCTRL_CHEN_Pos ) );
	hri_gclk_write_PCHCTRL_reg( GCLK, SERCOM0_GCLK_ID_SLOW, CONF_GCLK_SERCOM0_SLOW_SRC | ( 1 << GCLK_PCHCTRL_CHEN_Pos ) );
	hri_mclk_set_APBCMASK_SERCOM0_bit( MCLK );
	// SPI_LED_init
	spi_m_dma_init( &SPI_LED, SERCOM0 );												// init the DMA using HAL function
	// SPI_LED_PORT_init
	gpio_set_pin_direction( LED_MISO, GPIO_DIRECTION_IN );
	gpio_set_pin_pull_mode( LED_MISO, GPIO_PULL_OFF );
	gpio_set_pin_function( LED_MISO, PINMUX_PA04D_SERCOM0_PAD0 );
	gpio_set_pin_level( LED_SCLK, false );
	gpio_set_pin_direction( LED_SCLK, GPIO_DIRECTION_OUT );
	gpio_set_pin_function( LED_SCLK, PINMUX_PA05D_SERCOM0_PAD1 );
	gpio_set_pin_level( LED_MOSI, false );
	gpio_set_pin_direction( LED_MOSI, GPIO_DIRECTION_OUT );
	gpio_set_pin_function( LED_MOSI, PINMUX_PA07D_SERCOM0_PAD3 );
	// status LED init
	gpio_set_pin_function( STAT_LED, GPIO_PIN_FUNCTION_OFF );					// no special function on PIN
	gpio_set_pin_direction( STAT_LED, GPIO_DIRECTION_OUT );						// PIN setted as OUT
	gpio_set_pin_level( STAT_LED, false );												// turn OFF the status LED
	//
	spi_m_dma_register_callback( &SPI_LED, SPI_M_DMA_CB_TX_DONE, vUtil_DMA_transfer_SPI_LED );	// set the callback function for DMA operations
	spi_m_dma_enable( &SPI_LED );															// enable the DMA

	while( 1 ) {
		tx_stream[0] = 0x00;
		tx_stream[1] = 0x01;
		tx_stream[2] = 0x04;
		tx_stream[3] = 0x01;
		tx_stream[4] = 0x00;
		tx_stream[5] = 0x01;
		tx_stream[6] = 0x00;
		tx_stream[7] = 0x01;
		tx_stream[8] = 0x00;
		tx_stream[9] = 0x01;
		spi_m_dma_transfer( &SPI_LED, tx_stream, NULL, 10 );
		delay_short();
	}

	return 0;
}

Parents
  • This strongly suggests that there is some flaw in your code which you happen to get away with on GCC (Atmel Studio), but not on Keil.

    ie when the code "works", it just works by accident - not by design.

    2 key suspects would be:

    1. timing issues
    2. missing 'volatile'

    What optimisation settings are you using?

    If you try increasing the GCC optimisation level, does the code still "work" ... ?

    Apart from different compilers, you also have different linkers - so also check that your linker settings match.

    I think the startup code is also different between Atmel Studio & Keil uVision ?

    Have you tried it without DMA ?

    Whenever you have a working and a non-working version, the thing to do is to step through the code of each, and see where things diverge ...

    EDIT

    It may be worth also posting on the Microchip (Atmel) forum:

    https://community.atmel.com/forums/atmel-smart-arm-based-mcus

    As always when cross-posting, be sure to post links in both places to the other place - so that everyone can see the full picture - and keep both threads updated.

    EDIT 2

    The code does build cleanly in both cases - no errors & no warnings - doesn't it?

Reply
  • This strongly suggests that there is some flaw in your code which you happen to get away with on GCC (Atmel Studio), but not on Keil.

    ie when the code "works", it just works by accident - not by design.

    2 key suspects would be:

    1. timing issues
    2. missing 'volatile'

    What optimisation settings are you using?

    If you try increasing the GCC optimisation level, does the code still "work" ... ?

    Apart from different compilers, you also have different linkers - so also check that your linker settings match.

    I think the startup code is also different between Atmel Studio & Keil uVision ?

    Have you tried it without DMA ?

    Whenever you have a working and a non-working version, the thing to do is to step through the code of each, and see where things diverge ...

    EDIT

    It may be worth also posting on the Microchip (Atmel) forum:

    https://community.atmel.com/forums/atmel-smart-arm-based-mcus

    As always when cross-posting, be sure to post links in both places to the other place - so that everyone can see the full picture - and keep both threads updated.

    EDIT 2

    The code does build cleanly in both cases - no errors & no warnings - doesn't it?

Children