使用USB时,Atmel SAM D21 DMA卡在忙状态
我使用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中断优先级吗 代码:使用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的中断和
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;
}
}