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 hardware2- fill an array with fixed value3- send it using DMA4- a callback function blinks a LED when DMA has finished the data sending5- 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; }
Robert McNamara said:Your chip requires DMA transfer descriptors to be in LP SRAM.
You are right. I supposed that DMA descriptors were placed in LP SRAM (I verified that in Keil project LP SRAM is IRAM2).Now I modified my code adding a missing #define in saml21b/include/component/dmac.h file for ARM CC compiler:
#ifdef __GNUC__ #define SECTION_DMAC_DESCRIPTOR __attribute__ ((section(".lpram"))) #elif defined(__ICCARM__) #define SECTION_DMAC_DESCRIPTOR @".lpram" #elif defined(__CC_ARM) #define SECTION_DMAC_DESCRIPTOR __attribute__((section("IRAM2"))) #endif
then I cheched the "default" box next to IRAM2 in "Keil -> option for target -> Target"
so I supposed that the DmacDescriptor "_descriptor_section" and "_write_back_section" variables in hpl_dmac.c were placed in IRAM2
/* Section containing first descriptors for all DMAC channels */ COMPILER_ALIGNED(16) DmacDescriptor _descriptor_section[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR; /* Section containing current descriptors for all DMAC channels */ COMPILER_ALIGNED(16) DmacDescriptor _write_back_section[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR;
Unfortunatly these variables are still placed in SRAM (IRAM1 in Keil) so whats wrong?
To avoid this I setted the option "other data" in "hpl_dmac.c -> option for file -> memory assignment -> other data" to be "IRAM2". In this way the DMA is finally working, so I have a last question:How can I avoid to use the specific option for "hpl_dmac.c"?
Is there something wrong with #define SECTION_DMAC_DESCRIPTOR __attribute__((section("IRAM2")))
#define SECTION_DMAC_DESCRIPTOR __attribute__((section("IRAM2")))
Thanks for your help!