Puente PIC24FJ64GB002 UART

Trabajo en un proyecto pero tengo un problema.

Quiero hacer un programa que controle los dos UART en un PIC, cada UART a una velocidad de transmisión diferente. La idea es tomar una señal para UART1 (9600 baudios) y enviarla a la salida UART 2 (1200 baudios). En el momento hago un código para manejar los dos UART.

Adjunto el código, y esto tiene comentarios en la prueba de eco, y el uart funciona bien, cuando pongo datos en uart 2, estos datos están bien en la salida a UART 1, pero, cuando quiero poner datos en UART 1, para ver estos datos en la salida de uart 2, perdí muchos datos, por diferentes velocidades de transmisión. Espero que me entienda, mi problema es la pérdida de datos de alta tasa de baudios a baja tasa de baudios, espero su opinión sobre cómo resolver esto.

#if defined (__PIC24F__)
#include <p24FJ64GB002.h>
#endif
#include "xc.h"

_CONFIG4(DSBOREN_OFF & DSWDTEN_OFF)
_CONFIG3(WPDIS_WPDIS)
_CONFIG2(POSCMOD_NONE & OSCIOFNC_OFF & FNOSC_FRC & PLL96MHZ_OFF )
_CONFIG1(FWDTEN_OFF & JTAGEN_OFF)

 int c,D;


int main(void){


    //OSCILLATOR CONFIG
    OSCCON=0X0000;          //
    CLKDIVbits.RCDIV0=0; //clock divider to 0

    //PIN CONFIG

    AD1PCFGL=0XFFFF;            //ALL PINS DIGITAL
    TRISA = 0X0000;                  //PORT A OUTPUT
    TRISB = 0XFFFF;                  //PORT B INPUT

    RPOR2bits.RP5R=3;           // RP5  TX UART1
    RPOR3bits.RP6R=5;           // RP6  TX UART2

    RPINR18bits.U1RXR=0;        //RP0  RX UART1
    RPINR19bits.U2RXR=2;        //RP1  RX UART2

    //----------------------------------------------------------------------------

    //UART CONFIG

    U1BRG=103;
    U2BRG=832;

    U1MODEbits.UARTEN = 1; // UART Enable
    U1MODEbits.USIDL = 1;// Stop in Idle Mode Bit
    U1MODEbits.IREN = 0; // IrDA Encoder and Decoder Disabled
    U1MODEbits.RTSMD = 1; // UxRTS in SIMPLEX mode
    U1MODEbits.UEN = 00; // Tx and Rx pins are used,UxCTS,UxRTS, BCLK are controlled by port latch
    U1MODEbits.WAKE = 0; // Wake up disabled on sleep mode
    U1MODEbits.LPBACK = 0; // Loopback is disabled
    U1MODEbits.ABAUD = 0; // Baud rate measurement is disabled
    U1MODEbits.RXINV = 0; // Idle state is '1'
    U1MODEbits.BRGH =1; // High baurdate selected
    U1MODEbits.PDSEL = 00 ; // No parity, 8bits
    U1MODEbits.STSEL = 0; // 1 Stop bit

    U2MODEbits.UARTEN = 1; // UART Enable
    U2MODEbits.USIDL = 1;// Stop in Idle Mode Bit
    U2MODEbits.IREN = 0; // IrDA Encoder and Decoder Disabled
    U2MODEbits.RTSMD = 1; // UxRTS in SIMPLEX mode
    U2MODEbits.UEN = 00; // Tx and Rx pins are used,UxCTS,UxRTS, BCLK are controlled by port latch
    U2MODEbits.WAKE = 0; // Wake up disabled on sleep mode
    U2MODEbits.LPBACK = 0; // Loopback is disabled
    U2MODEbits.ABAUD = 0; // Baud rate measurement is disabled
    U2MODEbits.RXINV = 0; // Idle state is '1'
    U2MODEbits.BRGH =1; // High baurdate selected
    U2MODEbits.PDSEL = 00; // No parity, 8bits
    U2MODEbits.STSEL = 0; // 1 Stop bit

 //------------------------------------------------------------------

    //CONFIGURACION DE TRANSMISION, RECEPCION E INTERRUPCIONES DE LAS UART

    U1STAbits.UTXINV = 0; // UxTX idle state is '0'
    U1STAbits.UTXBRK = 0; // Sync Break Disabled
    U1STAbits.UTXEN = 1; // UART1 Transmitter  is enabled
    U1STAbits.URXISEL = 00; // Interrupt flag bit is set when a charater is received
    IEC0bits.U1TXIE = 0; // Disable UART1 Tx interrupt

    U2STAbits.UTXINV = 0; // UxTX idle state is '0'
    U2STAbits.UTXBRK = 0; // Sync Break Disabled
    U2STAbits.UTXEN = 1; // UART2 Transmitter  is enabled
    U2STAbits.URXISEL = 00; // Interrupt flag bit is set when a charater is received
    IEC1bits.U2TXIE=0;      // Disable UART2 Tx interrupt

         while(1){
//         //ECHO TEST UART 2 1200 BAUDS
//         //wait for byte
//         while(!U2STAbits.URXDA);
//         c=U2RXREG;//get byte
//         //wait for empty spot in transmit buffer
//         while(U2STAbits.UTXBF == 1);
//         //echo received character back
//         U2TXREG = c;


////         //ECHO TEST UART 1 9600 BAUDS
//         //wait for byte
//         while(!U1STAbits.URXDA);
//         D=U1RXREG;//get byte
//         //wait for empty spot in transmit buffer
//         while(U1STAbits.UTXBF == 1);
//         //echo received character back
//         U1TXREG = D;

//TEST TO PUT UT DATA FROM UART 2 1200 IN OUTPUT UART1 9600, ITS PART IS OK

         while(!U2STAbits.URXDA);
         D=U2RXREG;//get byte
         //wait for empty spot in transmit buffer
         while(U2STAbits.UTXBF == 1);
         //echo received character back
         U1TXREG = D;

         }

    return 0;
}

Respuestas (2)

Por lo que entiendo que estás preguntando, tienes 2 UART a diferentes velocidades. Envías datos al UART rápido, y este los envía a través del UART lento por ti, ¿y el problema que tienes es que pierdes datos porque no se envían lo suficientemente rápido?

De acuerdo. La respuesta es usar un sistema llamado "Store and Forward". Esto se ha utilizado durante muchos años en concentradores Ethernet 10/100, donde los datos que ingresan pueden ser 10 veces más rápidos que los datos que salen.

Básicamente, se trata de tener un búfer grande (normalmente circular) que se llena con el UART rápido y sale del UART lento.

Realmente solo funciona si tiene una forma de datos de "ráfaga", es decir, no está enviando datos todo el tiempo, sino enviando paquetes de fragmentos con demoras intermedias. Esto permite que el UART lento se ponga al día y haga espacio en el búfer circular para más datos.

En un sistema perfecto, usaría un apretón de manos para decirle al remitente rápido que deje de enviar por un tiempo. Lo mejor es el protocolo de enlace de hardware, en el que se utiliza una línea de E/S para señalar al remitente que se trata de datos "Listos para enviar" (CTS). Algunos chips (PIC32) tienen esta funcionalidad incorporada con pines CTS/RTS dedicados, pero es lo suficientemente simple como para emularla en aquellos que no la tienen.

Otra alternativa es utilizar el protocolo de enlace de software, también conocido como XON/XOFF, donde el PIC24 enviaría un carácter XOFF cuando su búfer esté casi lleno y un carácter XON cuando se esté vacía de nuevo. Estos niveles se conocen como "marca de agua alta" y "marca de agua baja" respectivamente, ya que todo el sistema se puede imaginar como un tanque que se llena con una tubería de gran diámetro y un pequeño orificio en el fondo que gotea agua. Una válvula cerraría el agua en la "marca de agua alta" y permitiría que fluya nuevamente en la "marca de agua baja".

Tenga en cuenta que la marca de agua alta no es lo mismo que el búfer lleno, solo "casi" lleno, ya que el protocolo de enlace del software no es perfecto y algunos datos aún pueden ingresar después de enviar XOF debido a cualquier búfer entre el software del remitente y el hardware del receptor.

Mientras espera un lugar vacío en el búfer tx para el UART lento, es probable que esté dejando que el búfer rx del UART más rápido se desborde al no procesar esos bytes lo suficientemente rápido. Una forma típica basada en software de hacer esto es crear su propio búfer en su software y leerlo/escribirlo sin bloquear la espera de la disponibilidad de rx/tx (otras soluciones son el protocolo de enlace como se describe en la respuesta de Majenko ) .

Un búfer circular es generalmente una solución fácil de implementar. Algo así como, pseudo-código:

unsigned char buffer[128];
int rxposition = 0, txposition = 0;

while (1) {

    /* If RX data, read it into our buffer. Otherwise do not wait. */
    if (U2STAbits.URXDA) {
        buffer[rxposition++] = U2RXREG;
        rxposition &= 127; /* Optimization of: rxposition %= sizeof(buffer); for size 128 */
    }

    /* If TX available and we have data to write, write it. Otherwise do not wait. */
    if (!U2STAbits.UTXBF && rxposition != txposition) {
        U1TXREG = buffer[txposition++];
        txposition &= 127; /* Optimization of: txposition %= sizeof(buffer); for size 128 */
    }

}

El fragmento anterior no contiene protección contra desbordamientos del búfer de entrada y tiene fines ilustrativos (ciertamente, desbordará el búfer de entrada si transmite datos continuamente al UART rápido; su velocidad de datos promedio al UART rápido todavía tiene que ser <= la lenta baudios para hacer posible su tarea), aunque vale la pena señalar que es posible que no necesite ningún tipo de protección adicional si dejar caer ~ sizeof(buffer)bloques arbitrarios de bytes en un desbordamiento es un comportamiento aceptable. Se eligió un tamaño de búfer de potencia de 2 solo para optimizar la operación del módulo, pero cualquier cosa servirá siempre que su búfer sea lo suficientemente grande para manejar su situación.

Gracias a Jason, procedo a implementar esta opción antes de obtener más información sobre "Almacenar y reenviar".