[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

ETRAX 100LX OS-less: more problems



Hi everybody!


Well, it pretty much works, apart from two nagging details.

My setup first:
One 100LX running Linux.  This has a simple program which shuffles
data between the Ethernet and serial ports.
One 100LX without OS.  This performs the same basic function, but
it inspects packets and only allows some of them through.
The boxes are linked over a serial line.  Each is connected to a
LAN (not the same one).
Both boxes send debug information on the serial 2 port.
The one running Linux I will refer to as the "inside", while the other
one is the "outside".

Problem number one occurs when I boot the "outside" machine up
while the "inside" machine is running my program.
During the "outside" boot, the "inside" machine starts screaming
"copy_descr_data: Buffer overflow!  512 bytes did not fit".  It says
this many times (the number of bytes varies) and then the debug
port hangs.  From what I can tell, the machine is still operational.
My program still runs and does its job, but nothing is sent to the
debug port.  Ever again.  I'm using minicom on a Linux PC to talk
to the 100LXes, and restarting minicom doesn't help.
Ultimately, of course, there will be no debug port open, so this is
not a very big deal, but it is annoying.

Problem number two is more serious.
The setup I have described above works well provided that I
connect the two 100LXes over an RS232 port (I have described
this problem before).  However, I would like to use the RS422, and
that doesn't work.  I can send from the "outside" to the "inside", but
not the other way, that is, the 422 port does not receive any data
when running without an OS: the receive DMA channel never
generates any interrupts
I have ruled out hardware problems.  It works when both boxes run
Linux.  I haven't been able to find anything in the serial driver
(serial.c)
that treats the 422 port differently from the 232, but clearly I am missing
something.
What?

I enclose relevant bits of the code.  Any help is appreciated.

Thanks,


/Ulf Sjöstedt
ulf.sjostedt@xxxxxxx.se



Assembler code first:

      ;; Set up genconfig.

      moveq 0,$r0

      ; Enable DMA channels 4 and 5 for serial port 3
      or.d  IO_STATE (R_GEN_CONFIG, dma5, serial3)    \
            | IO_STATE (R_GEN_CONFIG, dma4, serial3),$r0
      ; Enable serial port 3
      or.w  IO_STATE (R_GEN_CONFIG, ser3, select),$r0
      ; DEBUG: Enable serial port 2
      or.w  IO_STATE (R_GEN_CONFIG, ser2, select),$r0

      move.d      $r0,[genconfig_shadow]
      move.d      $r0,[R_GEN_CONFIG]


      ; Set up general ports.

      move.b      CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0
      move.b      $r0,[port_pa_dir_shadow]
      move.b      $r0,[R_PORT_PA_DIR]
      move.b      CONFIG_ETRAX_DEF_R_PORT_PA_DATA,$r0
      move.b      $r0,[port_pa_data_shadow]
      move.b      $r0,[R_PORT_PA_DATA]

      move.b      CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0
      move.b      $r0,[port_pb_config_shadow]
      move.b      $r0,[R_PORT_PB_CONFIG]
      move.b      CONFIG_ETRAX_DEF_R_PORT_PB_DIR,$r0
      move.b      $r0,[port_pb_dir_shadow]
      move.b      $r0,[R_PORT_PB_DIR]
      move.b      CONFIG_ETRAX_DEF_R_PORT_PB_DATA,$r0
      move.b      $r0,[port_pb_data_shadow]
      move.b      $r0,[R_PORT_PB_DATA]

      moveq 0,$r0
      move.d      $r0,[port_g_data_shadow]
      move.d      $r0,[R_PORT_G_DATA]

      ;; DEBUG: set up serial port 2

      moveq IO_STATE (R_SERIAL2_XOFF, tx_stop, enable)            \
            | IO_STATE (R_SERIAL2_XOFF, auto_xoff, disable)       \
            | IO_FIELD (R_SERIAL2_XOFF, xoff_char, 0),$r0
      move.d      $r0,[R_SERIAL2_XOFF]

      ; 115.2kbaud for both transmit and receive
      move.b IO_STATE (R_SERIAL2_BAUD, tr_baud, c115k2Hz)         \
            | IO_STATE (R_SERIAL2_BAUD, rec_baud, c115k2Hz),$r0
      move.b      $r0,[R_SERIAL2_BAUD]

      ; Set up and enable the serial2 receiver.
      move.b IO_STATE (R_SERIAL2_REC_CTRL, dma_err, stop)         \
            | IO_STATE (R_SERIAL2_REC_CTRL, rec_enable, enable)   \
            | IO_STATE (R_SERIAL2_REC_CTRL, rts_, active)         \
            | IO_STATE (R_SERIAL2_REC_CTRL, sampling, middle)     \
            | IO_STATE (R_SERIAL2_REC_CTRL, rec_stick_par, normal)      \
            | IO_STATE (R_SERIAL2_REC_CTRL, rec_par, even)        \
            | IO_STATE (R_SERIAL2_REC_CTRL, rec_par_en, disable)  \
            | IO_STATE (R_SERIAL2_REC_CTRL, rec_bitnr, rec_8bit),$r0
      move.b      $r0,[R_SERIAL2_REC_CTRL]

      ; Set up and enable the serial2 transmitter.
      move.b IO_FIELD (R_SERIAL2_TR_CTRL, txd, 0)                 \
            | IO_STATE (R_SERIAL2_TR_CTRL, tr_enable, enable)     \
            | IO_STATE (R_SERIAL2_TR_CTRL, auto_cts, disabled)    \
            | IO_STATE (R_SERIAL2_TR_CTRL, stop_bits, one_bit)    \
            | IO_STATE (R_SERIAL2_TR_CTRL, tr_stick_par, normal)  \
            | IO_STATE (R_SERIAL2_TR_CTRL, tr_par, even)          \
            | IO_STATE (R_SERIAL2_TR_CTRL, tr_par_en, disable)    \
            | IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0
      move.b      $r0,[R_SERIAL2_TR_CTRL]



      ; Set up interrupt handling.

      move.d      0x40030000,$r0
      move  $r0,$ibr
      move.d      0x40030400, $r1
1:    clear.d     [$r0+]
      cmp.d $r1, $r0
      blo   1b
      nop

      move.d timer_int,$r1
      move.d $r1,[0x40030088]
      move.d eth_err_int,$r1
      move.d $r1,[0x40030098]
      move.d $r1,[0x4003009c]
      move.d eth_tx_int,$r1
      move.d $r1,[0x400300c0]
      move.d eth_rx_int,$r1
      move.d $r1,[0x400300c4]
      move.d ser_tx_int,$r1
      move.d $r1,[0x400300d0]
      move.d ser_rx_int,$r1
      move.d $r1,[0x400300d4]

      ; Do C code initialization.
      jsr   _initialize


      ; All done.  Enable interrupts and go stand in the corner.

      ei

_corner:
      nop
      jump _corner



;; Interrupt handlers

timer_int:
      push $dccr
      di
    subq 14*4, $sp
      movem $r13,[$sp]
      jsr _timeout
      movem [$sp+],$r13
      reti
      pop $dccr

eth_err_int:
      push $dccr
      di
    subq 14*4, $sp
      movem $r13,[$sp]
      jsr _eth_err
      movem [$sp+],$r13
      reti
      pop $dccr

eth_tx_int:
      push $dccr
      di
    subq 14*4, $sp
      movem $r13,[$sp]
      jsr _eth_tx
      movem [$sp+],$r13
      reti
      pop $dccr

eth_rx_int:
      push $dccr
      di
    subq 14*4, $sp
      movem $r13,[$sp]
      jsr _eth_rx
      movem [$sp+],$r13
      reti
      pop $dccr

ser_tx_int:
      push $dccr
      di
    subq 14*4, $sp
      movem $r13,[$sp]
      jsr _ser_tx
      movem [$sp+],$r13
      reti
      pop $dccr

ser_rx_int:
      push $dccr
      di
    subq 14*4, $sp
      movem $r13,[$sp]
      jsr _ser_rx
      movem [$sp+],$r13
      reti
      pop $dccr


And then C:

      *R_SERIAL3_CTRL =
            IO_STATE(R_SERIAL3_CTRL, tr_baud, c1843k2Hz) |
            IO_STATE(R_SERIAL3_CTRL, rec_baud, c1843k2Hz) |
            IO_STATE(R_SERIAL3_CTRL, dma_err, ignore) |
            IO_STATE(R_SERIAL3_CTRL, rec_enable, enable) |
            IO_STATE(R_SERIAL3_CTRL, rts_, inactive) |
            IO_STATE(R_SERIAL3_CTRL, sampling, middle) |
            IO_STATE(R_SERIAL3_CTRL, rec_par_en, disable) |
            IO_STATE(R_SERIAL3_CTRL, rec_bitnr, rec_8bit) |
            IO_STATE(R_SERIAL3_CTRL, tr_enable, enable) |
            IO_STATE(R_SERIAL3_CTRL, auto_cts, disabled) |
            IO_STATE(R_SERIAL3_CTRL, stop_bits, one_bit) |
            IO_STATE(R_SERIAL3_CTRL, tr_par_en, disable) |
            IO_STATE(R_SERIAL3_CTRL, tr_bitnr, tr_8bit);
      *R_SERIAL3_XOFF =
          IO_STATE(R_SERIAL3_XOFF, auto_xoff, disable);

      dummy = *R_SERIAL3_READ;

      /* Mask all interrupts. */

      *R_VECT_MASK_CLR =
          0xffffffff;
      *R_IRQ_MASK0_CLR =
          0xffffffff;
      *R_IRQ_MASK1_CLR =
          0xffffffff;
      *R_IRQ_MASK2_CLR =
          0xffffffff;

      /* Reset and wait for DMA channels. */

      RESET_DMA(NETWORK_TX_DMA_NBR);
      RESET_DMA(NETWORK_RX_DMA_NBR);
      RESET_DMA(SER0_TX_DMA_NBR);
      RESET_DMA(SER0_RX_DMA_NBR);
      WAIT_DMA(NETWORK_TX_DMA_NBR);
      WAIT_DMA(NETWORK_RX_DMA_NBR);
      WAIT_DMA(SER0_TX_DMA_NBR);
      WAIT_DMA(SER0_RX_DMA_NBR);

      /* Unmask interrupts. */

      *R_VECT_MASK_SET =
          IO_STATE(R_VECT_MASK_SET, dma5, set) |
          IO_STATE(R_VECT_MASK_SET, dma4, set) |
          IO_STATE(R_VECT_MASK_SET, dma1, set) |
          IO_STATE(R_VECT_MASK_SET, dma0, set) |
          IO_STATE(R_VECT_MASK_SET, snmp, set) |
          IO_STATE(R_VECT_MASK_SET, timer0, set) |
          IO_STATE(R_VECT_MASK_SET, network, set);

      *R_IRQ_MASK0_SET =
          IO_STATE(R_IRQ_MASK0_SET, underrun, set) |
          IO_STATE(R_IRQ_MASK0_SET, excessive_col, set) |
          IO_STATE(R_IRQ_MASK0_SET, timer0, set);

      *R_IRQ_MASK2_SET =
          IO_STATE(R_IRQ_MASK2_SET, dma0_eop, set) |
          IO_STATE(R_IRQ_MASK2_SET, dma1_eop, set) |
          IO_STATE(R_IRQ_MASK2_SET, dma4_eop, set) |
          IO_STATE(R_IRQ_MASK2_SET, dma5_eop, set) |
          IO_STATE(R_IRQ_MASK2_SET, dma5_descr, set);


      /* Clear interrupts. */

      *R_DMA_CH0_CLR_INTR = IO_STATE(R_DMA_CH0_CLR_INTR, clr_eop, do);
      *R_DMA_CH1_CLR_INTR = IO_STATE(R_DMA_CH1_CLR_INTR, clr_eop, do);
      *R_DMA_CH4_CLR_INTR = IO_STATE(R_DMA_CH4_CLR_INTR, clr_eop, do);
      *R_DMA_CH5_CLR_INTR = IO_STATE(R_DMA_CH5_CLR_INTR, clr_eop, do) |
                            IO_STATE(R_DMA_CH5_CLR_INTR, clr_descr, do);


      /* Start DMA channels. */

      *R_DMA_CH0_FIRST = nextUnsentEthTx;
      *R_DMA_CH1_FIRST = nextReceivedEthRx;
      *R_DMA_CH4_FIRST = nextUnsentSerTx;
      *R_DMA_CH5_FIRST = nextReceivedSerRx;

      *R_DMA_CH0_CMD = IO_STATE(R_DMA_CH0_CMD, cmd, start);
      *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, start);
      *R_DMA_CH4_CMD = IO_STATE(R_DMA_CH4_CMD, cmd, start);
      *R_DMA_CH5_CMD = IO_STATE(R_DMA_CH5_CMD, cmd, start);


      /* Start timer. */

      *R_TIMER_CTRL =
          IO_FIELD(R_TIMER_CTRL, timerdiv0, 3) |
          IO_STATE(R_TIMER_CTRL, i0, clr) |
          IO_STATE(R_TIMER_CTRL, tm0, run) |
          IO_STATE(R_TIMER_CTRL, clksel0, c300Hz);