1 votos

Cómo desactivar la interrupción Serial Rx del hardware de arduino correctamente

Introducción:

Tengo un Arduino mega haciendo múltiples tareas , de las cuales Una función Lee datos de un sensor usando SPI . Cada como 10.000 leer o algo así, tengo 1 bit de error en los datos SPI . y he reducido el problema a la interrupción generada por la biblioteca de recepción de serie.

Así que..: Quiero desactivar la interrupción de RX1 mientras me ocupo del sensor SPI (unos 10us), y luego volver a activar el RX1 de nuevo a la normalidad.

Preguntas:

¡1- Si utilizo Serial1.end() y luego Serial1.begin() (el código fuente se muestra a continuación desde GitHub de arduino), mi suposición es que estas funciones toman demasiado tiempo para llevar a cabo ( en milis segundos ). y los datos en el búfer de hardware ya recibidos y preparados para ser enviados se pierden !

void HardwareSerial::begin(unsigned long baud, byte config)
{
  // Try u2x mode first
  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
  *_ucsra = 1 << U2X0;

  // hardcoded exception for 57600 for compatibility with the bootloader
  // shipped with the Duemilanove and previous boards and the firmware
  // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
  // be > 4095, so switch back to non-u2x mode if the baud rate is too
  // low.
  if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
  {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubrr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  _written = false;

  //set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
  config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
  *_ucsrc = config;

  sbi(*_ucsrb, RXEN0);
  sbi(*_ucsrb, TXEN0);
  sbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);
}

void HardwareSerial::end()
{
  // wait for transmission of outgoing data
  flush();

  cbi(*_ucsrb, RXEN0);
  cbi(*_ucsrb, TXEN0);
  cbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);

  // clear any received data
  _rx_buffer_head = _rx_buffer_tail;
}

2- ¿O debo deshabilitar las interrupciones de serial1 manualmente (como se muestra a continuación), y luego volver a habilitarlas. es esto seguro desde el punto de vista del microcontrolador? ¿qué sucede con los datos en el búfer de hardware y software?

 //disable Interrupts     
cbi(*_ucsrb, RXEN1);
cbi(*_ucsrb, TXEN1);
cbi(*_ucsrb, RXCIE1);
cbi(*_ucsrb, UDRIE1); 
//Do the SPI routine // 
//enable interrupts
sbi(*_ucsrb, RXEN1);
sbi(*_ucsrb, TXEN1);
sbi(*_ucsrb, RXCIE1);
cbi(*_ucsrb, UDRIE1);

Opción 3:

Desactivar las interrupciones globales CLI()

hacer la rutina SPI

Habilitar las intrusiones globales SEI()

1voto

Bernd Puntos 61

La forma estándar de tratar un problema como el que tienes es simplemente utilizar la desactivación y activación de la interrupción global. Como ya sabes que la interrupción UART puede corromper tu transacción SPI entonces debes estar preparado para el hecho de que cualquier interrupción pueda corromper la transacción SPI.

El único caso general en el que no utilizarías la desactivación/activación de la interrupción global es si también estuvieras utilizando interrupciones para soportar las transacciones SPI. Esta no es la respuesta definitiva para todas las situaciones porque seguramente hay aplicaciones especializadas en las que es necesario manejar de forma compleja las interrupciones permitidas/no permitidas/prioridades. Sin embargo tu caso no parece ser ese tipo de situación.

Cuando se utiliza la habilitación y deshabilitación de interrupciones globales en un contexto de programación en el que pueden o no estar habilitadas cuando se llama a un trozo de código en particular con una sección crítica, entonces es necesario preservar el estado existente del sistema de interrupción global después del estado crítico. En este caso el método adecuado para manejar secciones críticas de código es utilizar una secuencia de código como el siguiente pseudocódigo:

  1. Empujar la bandera del estado de la interrupción a la pila de la CPU
  2. Desactivar las interrupciones globales
  3. Comienza la sección crítica del código
  4. ....
  5. La sección crítica del código termina
  6. Restaurar el estado de la bandera de interrupción de la pila de la CPU

La manipulación de la bandera de habilitación de la interrupción como esta normalmente debe hacerse en el lenguaje ensamblador de la CPU. Los compiladores de C a menudo proporcionan un medio para invocar el código ensamblador necesario o han incorporado macros para hacer esta operación.

0voto

JW. Puntos 145

Sólo tienes que utilizar la API de transacciones SPI.

https://www.arduino.cc/en/Tutorial/SPITransaction

De lo contrario, sólo desactivar los bits RXCIEn de la UART debería ser suficiente, pero yo no asumiría que llamar a Serial end / begin es un problema de rendimiento. Intenta usar los estándares primero y evalúa si es un problema real antes de optimizar. La optimización prematura es la raíz de todos los males.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X