Thursday, February 3, 2011

The SeaTalk interface

The SeaTalk repeaters are used as backup displays, useful when the notebook and/or the outdoor monitor are not available for some reason. For example, in low battery situation when the more power hungry monitor has to be shut off. I first tried a custom 7-segment LED display for this function, but it proved unreadable in the sun. I then decided to go with Raymarine ST40 repeaters for their easy-to-read displays in all conditions.


I found all the information I needed on Thomas Knauf’s website (www.thomasknauf.de/seatalk.htm). The SeaTalk protocol is peculiar in that it requires 9-bit ‘bytes’ instead of the usual 8-bit, which is why it cannot be interfaced directly with a PC. The ATmega microprocessor has built-in support for 9-bit communication. The SeaTalk protocol requires that you set the 9th bit to 1 for the first byte of a command, and reset it to 0 for the remaining bytes of the same command.
I built the bidirectional interface described on Thomas Knauf’s website, even if I use it only one-way. For the transistors, I picked a 2N3904 (NPN) and a 2N3906 (PNP).


With this post, I begin to present some code examples for the Atmega128, using the WinAVR environment (http://winavr.sourceforge.net/). The following example shows how to send 5 SeaTalk commands that the repeaters can recognize, using interrupt-driven communication for efficiency. The SeaTalk bus is connected to the USART1 of the microprocessor. The commands are first built in a byte array before being sent to USART1, configured at 4800 baud per the SeaTalk protocol.

 /* Some inialization */
 volatile char stbuff[21];
 volatile uint8_t stindex = 0;
 uint16_t data;

 /* enable serial port UART1 */
 /* Set baud rate : 4800 @ 16 MHz */
 UBRR1L = (unsigned char)(207);
 /* Enable transmitter with 9 data bits  */
 UCSR1B = _BV(TXEN1) | _BV(UCSZ12);

 double stw = 5.9;  // speed through water (STW) in knots
 double depth = 50.0; // depth in feet
 double temp = 70.0;     // temperature in degrees F
 double awa = -32.0;  // apparent wind angle (AWA) in degrees
 double aws = 11.0;  // apparent wind speed (AWS) in knots

 // build the STW command
 data = (uint16_t)(stw * 10.0 + 0.5);
 stbuff[0] = 0x20;
 stbuff[1] = 0x01;
 stbuff[2] = data;
 stbuff[3] = data >> 8;
 // build the depth command
 data = (uint16_t)(depth * 10.0 + 0.5);
 stbuff[4] = 0x00;
 stbuff[5] = 0x02;
 stbuff[6] = 0x00;
 stbuff[7] = data;
 stbuff[8] = data >> 8;

 // build the temperature command
 data = (uint16_t)(temp * 10.0 + 0.5 + 100.0);
 stbuff[9] = 0x27;
 stbuff[10] = 0x01;
 stbuff[11] = data;
 stbuff[12] = data >> 8;
 // build the AWS command
 double dummy;
 uint8_t data8_1 = (uint8_t)aws;
 uint8_t data8_2 = (uint8_t)(modf(aws, &dummy) * 10.0 + 0.5);

 if(data8_2 == 10)
 {
   data8_1 += 1;
   data8_2 = 0;
 }
 stbuff[13] = 0x11;
 stbuff[14] = 0x01;
 stbuff[15] = data8_1;
 stbuff[16] = data8_2;

 // build the AWA command
 if(awa < 0.0)
  awa += 360.0;
 data = ((uint16_t)(awa + 0.5)) * 2;
 stbuff[17] = 0x10;
 stbuff[18] = 0x01;
 stbuff[19] = data >> 8;
 stbuff[20] = data;

 // enable the interrupt that fires when the USART1
 // is ready to accept a new character to send
 UCSR1B |= _BV(UDRIE1);

// This interrupt routine will be called 21 times then will disable itself.

// Once a value is written in the UDR1 register, the USART will take care of
// sending it on the bus and the processor will be free to do its own things

// until the USART reports (by firing a new interrupt) that it is ready to accept
// another byte.
ISR(USART1_UDRE_vect)
{
 // 4-5-4-4-4 : 21 bytes    1000-10000-1000-1000-1000   0-4-9-13-17
 switch(stindex)
 {
  case 0:
  case 4:
  case 9:
  case 13:
  case 17:
   UCSR1B |= _BV(TXB81); // set 9th bit to 1
   break;
  default:
   UCSR1B &= ~(_BV(TXB81));  // reset 9th bit to 0
 }
 if(stindex < 20)
  UDR1 = stbuff[stindex++];
 else
 {
  UDR1 = stbuff[20];
  stindex = 0;
  UCSR1B &= ~(_BV(UDRIE1));  // disable interrupt
 }
}
In the current installation, I use the ST40 Bidata repeater to show the boat speed through water (STW), but I cheat by sending the VMG value for depth, and the speed of the current for temperature. For the the ST40 wind repeater, I send the usual apparent wind angle, but I cheat again by sending the true wind speed value for AWS, as I like to see the AWA and TWS together on the same display.
The data sent to the repeaters are the running averages over the last 4 seconds, sent at the 10 Hz rate. However, the repeaters are internally refreshed only one time per second, and with a one second delay. The values newly displayed are thus the average of the first 4 seconds of the last period of 5 seconds (you have to read this twice).

1 comment:

  1. If anyone is interested in hooking up a B&G system, I did some work decoding the fastnet bus:
    http://www.oppedijk.com/bandg/fastnet

    ReplyDelete