使用定时器触发SPI通信

时间:2015-03-26 12:00:13

标签: timer triggers microcontroller spi dma

我试图使用恩智浦LPC1788微控制器上的定时器触发SPI通信。在DMA用户手册的功能中,它写道控制器可以使用定时器来触发DMA突发。但我无法找到在DMA控制器中配置触发源的提示。

我计划发送一个高频率的SPI命令,并使用DMA控制器以相同的频率读取结果SPI。转移应由计时器触发。这可能吗?

原因我可以在计时器ISR中实现传输。但控制器已经忙于做其他更重要的事情。

修改:

今天我有时间再次重试。我使用定时器3匹配0来计数1 kHz。然后我将DMA流3配置为源外设类型TIM3M0和目标连接类型SSP0 TX。定时器触发DMA传输一次,但随后禁用通道。

因此,当数据按预期传输一次时,配置接缝是正确的。所以我尝试为DMA配置循环模式。我发现DMA控制器中的链表配置是什么接缝完美的。我为自己添加了一个元素链接来关闭循环。现在如果我运行这个例子,定时器再次触发DMA通道,并且通信以尽可能快的无限循环开始。这也不是我想要存档的内容。为什么不等待源外设的触发条件。目前我认为这个微控制器是不可能的。

我在这里添加了当前的注册配置:

计时器配置

Timer3 register contents

DMA源外设选择

DMA source peripheral register

DMA流3配置

DMA stream 3 registers part 1

DMA stream 3 register part 2

编辑2:

我也认为这是可能的。你必须使用3个频道。

  1. 通道4 是内存到内存的传输。它由定时器3匹配0触发。任务是重新配置并启用通道3 通道5
  2. 通道3 用于存储器到SPI外设传输
  3. 通道5 也是用于最终重新配置通道4 的内存到内存传输。这个关闭循环
  4. 我现在添加了我正在测试的代码。该链条按预期运行一次。但重新启用链条还没有成功。我在链中添加了三个测试元素,以查看是否执行了get。你看到任何明显的错误吗? 问题是您必须在通道传输终止后用所有寄存器重新配置整个DMA通道。

        GPDMA_LLI_Type linkedListEntry[15];
        uint32_t specialControlSPI = 0x0;
        uint32_t specialControlEnable = 0x0;
        uint32_t specialConfigSPI = 0x0;
        uint32_t specialConfigEnable = 0x0;
        uint32_t specialConfigReenab = 0x0;
        uint32_t specialCotrolReenab = 0x0;
        uint32_t linkedListEnab = 0x0;
        uint32_t linkedListReenab = 0x0;
        uint32_t myTest = 0x0;
        uint32_t myTest2 = 0x0;
        uint32_t srcDataRegisterSPI = 0x0;
        uint32_t srcDataRegisterEnab= 0x0;
        uint32_t srcDataRegisterReenab = 0x0;
        uint32_t destDataRegisterEnab= 0x0;
        uint32_t destDataRegisterReenab = 0x0;
        const uint32_t pattern1 = 0xAABBCCDD;
        const uint32_t pattern2 = 0xEEFF0088;
    
        #define MEMORY_TRANSFER_BURST (GPDMA_BSIZE_1)
        #define MEMORY_TRANSFER_WIDTH (GPDMA_WIDTH_WORD)
    
        void configureDMA_ForSPI_ADC_Tx(DMA dmaTx, void* data, uint32_t size)
        {
            //Disable all required channels 
            GPDMA_ChannelCmd(3, DISABLE); 
            GPDMA_ChannelCmd(4, DISABLE); 
            GPDMA_ChannelCmd(5, DISABLE); 
    
            //Form spcecial control for "enable" channel
            uint32_t specialControl = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
    
            uint32_t j = 0;
            //Configure "enable" channel to be triggered by timer 3 match 0 resulting in a memory transfer
            GPDMA_Channel_CFG_Type conf;
            conf.ChannelNum = 4;
            conf.DstConn = 0;
            conf.SrcConn = GPDMA_CONN_MAT3_0;
            conf.TransferType = GPDMA_TRANSFER_M2M_CTRL_DMA;
            conf.SrcMemAddr = (uint32_t)&specialControlSPI;
            conf.TransferSize = 4;
            conf.DstMemAddr = (uint32_t)&LPC_GPDMACH3->CControl;
            conf.DMALLI = (uint32_t)&linkedListEntry[j],
            GPDMA_Setup(&conf, &specialControl);     
    
            //Prepare linked list to enable "enable" channel again
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH3->CSrcAddr; 
            linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterSPI;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH3->CConfig;     ///Enable SPI channel
            linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigSPI;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CControl; 
            linkedListEntry[j].SrcAddr = (uint32_t)&specialCotrolReenab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CLLI; 
            linkedListEntry[j].SrcAddr = (uint32_t)&linkedListReenab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CDestAddr; 
            linkedListEntry[j].SrcAddr = (uint32_t)&destDataRegisterReenab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;    
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CSrcAddr; 
            linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterReenab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CConfig;    ///Enable "Reenable" channel
            linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigReenab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;        
    
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH7->CControl;   
            linkedListEntry[j].SrcAddr = (uint32_t)&pattern1;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;        
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&myTest; 
            linkedListEntry[j].SrcAddr = (uint32_t)&pattern1;
            linkedListEntry[j].NextLLI = 0;        
            j++;
    
    
            //------------------------------------------------------------------------------------------------------------------
    
            //Form special control for "SPI" channel
            specialControl = GPDMA_DMACCxControl_TransferSize(size) \
                    | GPDMA_DMACCxControl_SBSize((uint32_t)GPDMA_BSIZE_1)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)GPDMA_BSIZE_1)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)GPDMA_WIDTH_HALFWORD)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)GPDMA_WIDTH_HALFWORD)
                    | GPDMA_DMACCxControl_SI;
    
    
            //Configure "SPI" channel to be triggered by software resulting in a peripheral transfer and a memory transfer in linked list
            conf.ChannelNum = 3;
            conf.DMALLI = 0,
            conf.DstConn = GPDMA_CONN_SSP0_Tx;
            conf.SrcConn = 0;
            conf.TransferType = GPDMA_TRANSFER_M2P_CTRL_DMA;
            conf.SrcMemAddr = (uint32_t)data;
            conf.TransferSize = size;
            conf.DstMemAddr = 0; 
            GPDMA_Setup(&conf, &specialControl);
    
            //------------------------------------------------------------------------------------------------------------------
            //Form special control for "reenab" channel
            specialControl = GPDMA_DMACCxControl_TransferSize(size) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
    
            //Configure "SPI" channel to be triggered by software resulting in a peripheral transfer and a memory transfer in linked list
            conf.ChannelNum = 5;
            conf.DstConn = 0;
            conf.SrcConn = 0;
            conf.TransferType = GPDMA_TRANSFER_M2M_CTRL_DMA;
            conf.TransferSize = 4;
            conf.SrcMemAddr = (uint32_t)&specialControlEnable;
            conf.DstMemAddr = (uint32_t)&LPC_GPDMACH4->CControl;
            conf.DMALLI = (uint32_t)&linkedListEntry[j],
            GPDMA_Setup(&conf, &specialControl);
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CLLI; 
            linkedListEntry[j].SrcAddr = (uint32_t)&linkedListEnab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CDestAddr; 
            linkedListEntry[j].SrcAddr = (uint32_t)&destDataRegisterEnab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CSrcAddr; 
            linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterEnab;
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            //Prepare linked list to enable "enable" channel again
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CConfig;
            linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigEnable;   ///Enable trigger channel again
            linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
            j++;
    
            linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) 
                    | GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
                    | GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
                    | GPDMA_DMACCxControl_SI
                    | GPDMA_DMACCxControl_DI;
            linkedListEntry[j].DstAddr = (uint32_t)&myTest2; 
            linkedListEntry[j].SrcAddr = (uint32_t)&pattern2;
            linkedListEntry[j].NextLLI = 0;
            j++;
    
            //Store the configuration registers for DMA operation
            specialControlSPI    = LPC_GPDMACH3->CControl | GPDMA_DMACCxControl_TransferSize(size);
            specialControlEnable = LPC_GPDMACH4->CControl | GPDMA_DMACCxControl_TransferSize(4);
            specialCotrolReenab  = LPC_GPDMACH5->CControl | GPDMA_DMACCxControl_TransferSize(4);
    
            srcDataRegisterSPI =  LPC_GPDMACH3->CSrcAddr;
            srcDataRegisterEnab = LPC_GPDMACH4->CSrcAddr;
            srcDataRegisterReenab = LPC_GPDMACH5->CSrcAddr;
    
            destDataRegisterEnab = LPC_GPDMACH4->CDestAddr;
            destDataRegisterReenab = LPC_GPDMACH5->CDestAddr;
    
            specialConfigSPI    = (0x1) | LPC_GPDMACH3->CConfig; 
            specialConfigEnable = (0x1) | LPC_GPDMACH4->CConfig;   
            specialConfigReenab = (0x1) | LPC_GPDMACH5->CConfig;  
    
            linkedListReenab = LPC_GPDMACH5->CLLI;
            linkedListEnab = LPC_GPDMACH4->CLLI;
    
            //Enable the channel "enable" channel. Hopfully will be triggered by timer match soon. This should enable SPI transfer
            GPDMA_ChannelCmd(4, ENABLE);
        }
    

0 个答案:

没有答案