使用USB时,Atmel SAM D21 DMA卡在忙状态

使用USB时,Atmel SAM D21 DMA卡在忙状态,usb,atmel,dma,asf,Usb,Atmel,Dma,Asf,我使用SAMD21 Explained pro和一个原型来采集信号,使用内部ADC和DMAC,配置为采集5500个样本。 然后,样本通过目标USB传输到PC应用程序 我为其编写的固件正在工作,但我注意到DMA不时会陷入忙碌状态。 为了调试,我取消了通过USB传输到PC的部分 我注意到DMA工作正常,并将样本传输到内存,但如果我将USB电缆连接到PC(不通过USB传输数据),DMA会不时卡住; 但一旦我断开(目标)USB电缆,DMA就会连续工作,而不会陷入忙碌状态 我怀疑它与USB和ADC的中断和

我使用SAMD21 Explained pro和一个原型来采集信号,使用内部ADC和DMAC,配置为采集5500个样本。 然后,样本通过目标USB传输到PC应用程序

我为其编写的固件正在工作,但我注意到DMA不时会陷入忙碌状态。 为了调试,我取消了通过USB传输到PC的部分

我注意到DMA工作正常,并将样本传输到内存,但如果我将USB电缆连接到PC(不通过USB传输数据),DMA会不时卡住; 但一旦我断开(目标)USB电缆,DMA就会连续工作,而不会陷入忙碌状态

我怀疑它与USB和ADC的中断和优先级有关,两者都使用DMA。 我想我应该将ADC采样设置为最高优先级,这样USB就不会导致DMA卡在忙状态,但我在代码中找不到如何配置它(我使用的是ASF)

你知道为什么插上USB会导致DMA偶尔陷入忙碌状态吗? 如果这个问题与我所怀疑的优先级有关,你知道如何降低USB中断优先级吗

代码:

void gswatchmain流程(void)
{
静态int i=0;
gspackettostream;
开关(敲打机器)
{
爆震案例:
KnockKnockStateMachine=KnockKnockStandby;
打破
待命案件:
如果(StreamADC&!RequestForAcknowledge)knockStateMachine=WakeupAphrodite;
knockStateMachine=WakeupAphrodite;//添加此行是为了跳过等待来自PC的命令
打破
阿芙罗狄蒂案:
如果(dma_忙(&示例_资源))
{
knockStateMachine=中止knockknock;
}
其他的
{
端口\引脚\设置\输出\电平(引脚\ PB09,真);
端口引脚设置输出电平(LED引脚0,错误);
传输完成=错误;
if(dma\u启动\u传输\u作业(&示例\u资源))
{
knockStateMachine=中止knockknock;
}
}
knockStateMachine=WaitForBurstToEnd;
i=200000;//当DMA超时后卡住时,此计数器用作重置DMA的变通方法
打破
案件等待审理日期:
如果(!dma_忙(&示例_资源))
{
knockstatemachine=ProcessBurst;
}
if(!--i)//在DMA卡滞时重新设置DMA
{
knockStateMachine=中止knockknock;
}
打破
案例处理突发事件:
PacketToStream.Type=流;
PacketToStream.ContentLength=0;
对于(i=0;i=PACKET\u MAX\u SIZE)
{
//SendViaGSWatchLink(PacketToStream);
PacketToStream.ContentLength=0;
}
}
//如果(PacketToStream.ContentLength>0)发送viagswatchlink(PacketToStream);
RequestForAcknowledge=true;
KnockKnockStateMachine=KnockKnockStandby;
打破
案例中止敲打:
dma_中止_作业(&示例_资源);
无dma(示例资源);
端口\引脚\设置\输出\电平(引脚\ PB09,错误);
端口\引脚\设置\输出\电平(LED\ 0\引脚,真);
传输完成=真;
配置\u dma\u资源(&示例\u资源);
设置\u传输\u描述符(&DMA\u ADC\u描述符);
dma_添加_描述符(&示例_资源,&dma_ADC_描述符);
dma_寄存器_回调(示例_资源、传输_完成、dma_回调_传输_完成);
dma\u启用\u回调(示例\u资源,dma\u回调\u传输\u完成);
系统中断启用全局();
knockStateMachine=唤醒阿佛洛狄忒;
打破
}
}
无效传输完成(结构dma资源*常量资源)
{
传输完成=真;
端口\引脚\设置\输出\电平(引脚\ PB09,错误);
端口\引脚\设置\输出\电平(LED\ 0\引脚,真);
}
无效设置\传输\描述符(DmacDescriptor*描述符)
{
结构dma_描述符_配置描述符_配置;
dma_描述符_获取_配置_默认值(&描述符_配置);
描述符\u config.beat\u size=DMA\u beat\u size\u硬件;
描述符\u config.block\u传输\u计数=ADC\u样本;
descriptor_config.dst_increment_enable=true;
descriptor\u config.src\u increment\u enable=false;
描述符_config.source_address=(uint32_t)(&adc_instance.hw->RESULT.reg);
//描述符_config.destination_address=(uint32_t)adc_结果_缓冲区+2*adc_样本;
描述符_config.destination_address=(uint32_t)adc_result_buffer+sizeof(adc_result_buffer);
dma_描述符_创建(描述符和描述符_配置);
}
无效配置\u dma\u资源(结构dma\u资源*资源)
{
结构dma\u资源配置\u dma;
dma_get_config_默认值(&config_dma);
config_dma.peripheral_trigger=ADC_DMAC_ID_RESRDY;
config_dma.trigger_action=dma_trigger_action_BEAT;
config_dma.priority=dma_priority_LEVEL_3;
dma_分配(资源和配置_dma);
}
无效配置\u adc(无效)
{
结构adc\u配置adc;
adc\u获取\u配置\u默认值(&config\u adc);
//config\u adc.gain\u factor=adc\u gain\u factor\u DIV2;//TODO:检查是否需要此功能
config\u adc.clock\u prescaler=adc\u clock\u prescaler\u DIV32;//TODO:检查是否可以使用8
config_adc.reference=adc_reference_INTVCC0;//adc_reference_INT1V;//adc_reference_INTVCC1;
config_adc.positive_input=adc_positive_input_PIN8;
config_adc.negative_input=adc_negative_input_GND;
config_adc.resolution=adc_resolution_12BI
void GSWatchMainProcess(void)
{
    static int i=0;

    GSPacket PacketToStream;

    switch (KnockKnockStateMachine)
    {
        case InitKnockKnock:
            KnockKnockStateMachine = KnockKnockStandby;
            break;

        case KnockKnockStandby:
            if (StreamADC && !RequestForAcknowledge) KnockKnockStateMachine = WakeupAphrodite;
            KnockKnockStateMachine = WakeupAphrodite;       //this line was added to skip waiting for a command from the PC
            break;

        case WakeupAphrodite:
            if (dma_is_busy(&example_resource))
            {
                KnockKnockStateMachine = AbortKnockKnock;
            }
            else
            {
                port_pin_set_output_level(PIN_PB09, true);
                port_pin_set_output_level(LED_0_PIN, false);
                transfer_is_done = false;
                if(dma_start_transfer_job(&example_resource))
                {
                    KnockKnockStateMachine = AbortKnockKnock;
                }
            }

            KnockKnockStateMachine = WaitForBurstToEnd;
            i=200000;       //this counter is used as work-around to reset the DMA when it get stuck after timeout
            break;

        case WaitForBurstToEnd:
            if (!dma_is_busy(&example_resource))
            {
                KnockKnockStateMachine = ProcessBurst;
            }
            if(!--i)        // work-around to reset DMA when it get stuck
            {
                KnockKnockStateMachine = AbortKnockKnock;
            }
            break;

        case ProcessBurst:
            PacketToStream.Type=Stream;
            PacketToStream.ContentLength=0;
            for (i = 0; i<(ADC_SAMPLES); i++)
            {
                PacketToStream.Content[PacketToStream.ContentLength++] = adc_result_buffer[i] / 256;
                PacketToStream.Content[PacketToStream.ContentLength++] = adc_result_buffer[i] % 256;
                if(PacketToStream.ContentLength>=PACKET_MAX_SIZE)
                {
                    //SendViaGSWatchLink(PacketToStream);
                    PacketToStream.ContentLength=0;
                }
            }
            //if(PacketToStream.ContentLength>0) SendViaGSWatchLink(PacketToStream);
            RequestForAcknowledge = true;
            KnockKnockStateMachine = KnockKnockStandby;
            break;

        case AbortKnockKnock:
            dma_abort_job(&example_resource);
            dma_free(&example_resource);
            port_pin_set_output_level(PIN_PB09, false);
            port_pin_set_output_level(LED_0_PIN, true);
            transfer_is_done = true;

            configure_dma_resource(&example_resource);
            setup_transfer_descriptor(&DMA_ADC_descriptor);
            dma_add_descriptor(&example_resource, &DMA_ADC_descriptor);
            dma_register_callback(&example_resource, transfer_done, DMA_CALLBACK_TRANSFER_DONE);
            dma_enable_callback(&example_resource, DMA_CALLBACK_TRANSFER_DONE);
            system_interrupt_enable_global();

            KnockKnockStateMachine = WakeupAphrodite;
            break;
    }
}




void transfer_done(struct dma_resource* const resource )
{
    transfer_is_done = true;
    port_pin_set_output_level(PIN_PB09, false);
    port_pin_set_output_level(LED_0_PIN, true);

}
void setup_transfer_descriptor(DmacDescriptor *descriptor)
{
    struct dma_descriptor_config descriptor_config;
    dma_descriptor_get_config_defaults(&descriptor_config);
    descriptor_config.beat_size = DMA_BEAT_SIZE_HWORD;
    descriptor_config.block_transfer_count = ADC_SAMPLES;
    descriptor_config.dst_increment_enable = true;
    descriptor_config.src_increment_enable = false;
    descriptor_config.source_address = (uint32_t)(&adc_instance.hw->RESULT.reg);
    //descriptor_config.destination_address = (uint32_t)adc_result_buffer + 2 * ADC_SAMPLES;
    descriptor_config.destination_address = (uint32_t)adc_result_buffer + sizeof(adc_result_buffer);
    dma_descriptor_create(descriptor, &descriptor_config);
}
void configure_dma_resource(struct dma_resource *resource)
{
    struct dma_resource_config config_dma;
    dma_get_config_defaults(&config_dma);
    config_dma.peripheral_trigger = ADC_DMAC_ID_RESRDY;
    config_dma.trigger_action = DMA_TRIGGER_ACTON_BEAT;
    config_dma.priority = DMA_PRIORITY_LEVEL_3;
    dma_allocate(resource, &config_dma);
}
void configure_adc(void)
{
    struct adc_config config_adc;
    adc_get_config_defaults(&config_adc);
    //  config_adc.gain_factor          = ADC_GAIN_FACTOR_DIV2;  //TODO: check if we need this feature
    config_adc.clock_prescaler      = ADC_CLOCK_PRESCALER_DIV32; //TODO: check whether it possible to work with 8
    config_adc.reference            = ADC_REFERENCE_INTVCC0; //ADC_REFERENCE_INT1V; //ADC_REFERENCE_INTVCC1;
    config_adc.positive_input       = ADC_POSITIVE_INPUT_PIN8;
    config_adc.negative_input       = ADC_NEGATIVE_INPUT_GND;
    config_adc.resolution           = ADC_RESOLUTION_12BIT;
    config_adc.sample_length        = 0;    //4
    config_adc.differential_mode    = false;
    config_adc.freerunning          = true;

    adc_init(&adc_instance, ADC, &config_adc);
    adc_enable(&adc_instance);
}
transfer_tx_is_done=0;
dma_start_transfer_job(&res_2_Byte);

while (!transfer_tx_is_done) {
    /* Wait for transfer done */
    if (SPI_done())
    {
        res_2_Byte.job_status=STATUS_OK;
        break;
    }
}