Forum: Mikrocontroller und Digitale Elektronik Atmel xmega USB, Interrupt disabled / enabled / Latenz


von Wolfgang K. (opendcc)


Lesenswert?

Hallo,

ich wühle mich gerade durch das Keyboard-Bespiel aus dem ASF und rätsle 
über die Notwendigkeit des Verriegels des Interruptsystems. Hintergrund: 
ich kann aus anderen Gründe keine allzu lange Zeit im Disabled-Zustand 
zulassen.


Atmel hat da Zugriffsroutinen auf den Keyboardreport definiert, hier mal 
als Beispiel der Modifiereintrag:
1
bool udi_hid_kbd_modifier_up(uint8_t modifier_id)
2
{
3
  irqflags_t flags = cpu_irq_save();
4
5
  // Fill report
6
  udi_hid_kbd_report[0] &= ~(unsigned)modifier_id;
7
  udi_hid_kbd_b_report_valid = true;
8
9
  // Send report
10
  udi_hid_kbd_send_report();
11
12
  cpu_irq_restore(flags);
13
  return true;
14
}
Hier machen sie also cli(), dann das Bit eintragen, dann kommt 
udi_hid_kbd_send_report():
1
static bool udi_hid_kbd_send_report(void)    // runs in disabled int
2
{
3
  if (udi_hid_kbd_b_report_trans_ongoing)
4
    return false;
5
  memcpy(udi_hid_kbd_report_trans, udi_hid_kbd_report,
6
      UDI_HID_KBD_REPORT_SIZE);
7
  udi_hid_kbd_b_report_valid = false;
8
  udi_hid_kbd_b_report_trans_ongoing =
9
      udd_ep_run(  UDI_HID_KBD_EP_IN,
10
              false,
11
              udi_hid_kbd_report_trans,
12
              UDI_HID_KBD_REPORT_SIZE,
13
              udi_hid_kbd_report_sent);
14
  return udi_hid_kbd_b_report_trans_ongoing;
15
}

Hier geht es, wenn möglich, nach udd_ep_run() = Endpoint run. Endpoint 
run ist dann eine länger Geschichte:
1
bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket, uint8_t * buf,
2
    iram_size_t buf_size, udd_callback_trans_t callback)
3
{
4
  udd_ep_job_t *ptr_job;
5
  irqflags_t flags;
6
  UDD_EP_t *ep_ctrl;
7
8
  Assert(udd_ep_is_valid(ep));
9
10
  // Get control & job about this endpoint
11
  ptr_job = udd_ep_get_job(ep);
12
  ep_ctrl = udd_ep_get_ctrl(ep);
13
14
  if (!udd_endpoint_is_enable(ep_ctrl)) {
15
    return false; // Endpoint not allocated
16
  }
17
  if (udd_endpoint_get_type(ep_ctrl)!=USB_EP_TYPE_ISOCHRONOUS_gc
18
    && udd_endpoint_is_stall(ep_ctrl)) {
19
    return false; // Endpoint is halted
20
  }
21
  flags = cpu_irq_save();          // endpoint run
22
  if (ptr_job->busy == true) {
23
    cpu_irq_restore(flags);
24
    return false; // Job already on going
25
  }
26
  ptr_job->busy = true;
27
  cpu_irq_restore(flags);
28
29
30
  // Update Job information
31
  ptr_job->buf = buf;
32
  ptr_job->buf_size = buf_size;
33
  ptr_job->nb_trans = 0;
34
  ptr_job->call_trans = callback;
35
  // Need to enable shortpacket to send a ZLP (buf_size==0)
36
  ptr_job->b_shortpacket = b_shortpacket || (buf_size==0);
37
  ptr_job->b_use_out_cache_buffer = false;
38
39
  // Initialize value to simulate a empty transfer
40
  if (USB_EP_DIR_IN == (ep & USB_EP_DIR_IN)) {
41
    udd_endpoint_in_reset_nb_sent(ep_ctrl);
42
  }
43
  else
44
  {
45
    if ((USB_EP_TYPE_ISOCHRONOUS_gc == udd_endpoint_get_type(ep_ctrl))
46
    && (0 != (buf_size % udd_ep_get_size(ep_ctrl)))) {
47
      // The user must use a buffer size modulo endpoint size
48
      ptr_job->busy = false;
49
      return false;
50
    }
51
    udd_endpoint_out_reset_nb_received(ep_ctrl);
52
    udd_endpoint_out_set_nbbyte(ep_ctrl, 0);
53
  }
54
  // Request next transfer
55
  udd_ep_trans_complet(ep);
56
  return true;
57
}
Hier ist die eigentlich kritische Geschichte, nämlich kontrollieren ob 
ptr_job->busy == true ist, nochmals mit cli()-restore geklammert. 
Brauche ich dann die äußere Verriegelung bei udi_hid_kbd_modifier_up? 
Oder soll die nur reentry verhindern?

Gruß Wolfgang

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.