{"id":408,"date":"2012-10-28T16:25:02","date_gmt":"2012-10-28T16:25:02","guid":{"rendered":"http:\/\/ava.upuaut.net\/?p=408"},"modified":"2012-10-28T17:05:28","modified_gmt":"2012-10-28T17:05:28","slug":"coding-interrupt-driven-rtty-transmission-on-arduinoavr","status":"publish","type":"post","link":"https:\/\/ava.upuaut.net\/?p=408","title":{"rendered":"Coding : Interrupt Driven RTTY Transmission on Arduino\/AVR"},"content":{"rendered":"<p>One of the things on my\u00a0to-do\u00a0list has been convert the transmission of the RTTY into the background as an interrupt. When the payload is transmitting at 50 baud it effectively sits around doing nothing for 15 seconds whilst it transmits.<\/p>\n<p>By moving this to an interrupt based routine it can transmit in the background whilst allowing the foreground \u00a0tasks to run. This means more data being logged, more accurate altitude measurements, faster response to a burst if needed etc.<\/p>\n<p>Having had a good read of\u00a0<a href=\"http:\/\/www.engblaze.com\/microcontroller-tutorial-avr-and-arduino-timer-interrupts\/\">http:\/\/www.engblaze.com\/microcontroller-tutorial-avr-and-arduino-timer-interrupts\/<\/a>\u00a0I set about coding up the code to do this one step at a time. Firstly I replicated the high\/low code from\u00a0<a href=\"http:\/\/ukhas.org.uk\/guides:linkingarduinotontx2#part_1_-_test_circuit_and_test_code\">http:\/\/ukhas.org.uk\/guides:linkingarduinotontx2#part_1_-_test_circuit_and_test_code<\/a><\/p>\n<p>After finding a few code timing errors I think I&#8217;ve sorted it out so it runs as a stand alone procedure which TX&#8217;s in the back ground. The RFM22B seemed to struggle to switch frequencies fast enough above 300 baud using radio1.setFrequency(RADIO_FREQUENCY_LOW)\/radio1.setFrequency(RADIO_FREQUENCY_HIGH). Dave Akerman suggested (as recommended by Navrac) that using the shift frequency register is better way. Indeed it is much faster, results in a much cleaner signal and allowed the baud rate to decode fine up to 600. <\/p>\n<p>So here is what I&#8217;ve come up with, it will need further testing and integration into my existing flight code.<\/p>\n<pre class=\"brush: cpp; title: ; notranslate\" title=\"\">\r\n\r\n\/*\r\n Interrupt Driven RTTY TX Demo\r\n \r\n Transmits data via RTTY with an interupt driven subroutine.\r\n \r\n By Anthony Stirk M0UPU \r\n \r\n October 2012 Version 5\r\n \r\n Thanks and credits :\r\n Evolved from Rob Harrison's RTTY Code.\r\n Compare match register calculation by Phil Heron.\r\n Thanks to : http:\/\/www.engblaze.com\/microcontroller-tutorial-avr-and-arduino-timer-interrupts\/\r\n RFM22B Code from James Coxon http:\/\/ukhas.org.uk\/guides:rfm22b \r\n Suggestion to use Frequency Shift Registers by Dave Akerman (Daveake)\/Richard Cresswell (Navrac)\r\n \r\n This program is free software: you can redistribute it and\/or modify\r\n it under the terms of the GNU General Public License as published by\r\n the Free Software Foundation, either version 3 of the License, or\r\n (at your option) any later version.\r\n \r\n This program is distributed in the hope that it will be useful,\r\n but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r\n GNU General Public License for more details.\r\n \r\n See &lt;http:\/\/www.gnu.org\/licenses\/&gt;.\r\n *\/\r\n#include &lt;avr\/io.h&gt;\r\n#include &lt;avr\/interrupt.h&gt;\r\n#include &lt;util\/crc16.h&gt;\r\n#include &lt;SPI.h&gt;\r\n#include &lt;RFM22.h&gt;\r\n\r\n#define ASCII 7          \/\/ ASCII 7 or 8\r\n#define STOPBITS 2       \/\/ Either 1 or 2\r\n#define TXDELAY 0        \/\/ Delay between sentence TX's\r\n#define RTTY_BAUD 100    \/\/ Baud rate for use with RFM22B Max = 600\r\n#define RADIO_FREQUENCY 434.198\r\n\r\n\r\n#define RFM22B_SDN 3\r\n#define RFM22B_PIN 10\r\n\r\nchar datastring&#x5B;80];\r\nchar txstring&#x5B;80];\r\nvolatile int txstatus=1;\r\nvolatile int txstringlength=0;\r\nvolatile char txc;\r\nvolatile int txi;\r\nvolatile int txj;\r\nunsigned int count=0;\r\n\r\n\r\nrfm22 radio1(RFM22B_PIN);\r\n\r\nvoid setup()\r\n{\r\n  initialise_interrupt();\r\n  setupRadio();\r\n}\r\n\r\nvoid loop()\r\n{\r\n\r\n  sprintf(datastring,&quot;$$$$$M0UPU,%04u,RTTY TEST BEACON RTTY TEST BEACON&quot;,count); \/\/ Puts the text in the datastring\r\n  unsigned int CHECKSUM = gps_CRC16_checksum(datastring);  \/\/ Calculates the checksum for this datastring\r\n  char checksum_str&#x5B;6];\r\n  sprintf(checksum_str, &quot;*%04X\\n&quot;, CHECKSUM);\r\n  strcat(datastring,checksum_str);\r\n  delay(1000);\r\n  count++;\r\n}\r\n\r\nISR(TIMER1_COMPA_vect)\r\n{\r\n  switch(txstatus) {\r\n  case 0: \/\/ This is the optional delay between transmissions.\r\n    txj++;\r\n    if(txj&gt;(TXDELAY*RTTY_BAUD)) { \r\n      txj=0;\r\n      txstatus=1;\r\n    }\r\n    break;\r\n  case 1: \/\/ Initialise transmission, take a copy of the string so it doesn't change mid transmission. \r\n    strcpy(txstring,datastring);\r\n    txstringlength=strlen(txstring);\r\n    txstatus=2;\r\n    txj=0;\r\n    break;\r\n  case 2: \/\/ Grab a char and lets go transmit it. \r\n    if ( txj &lt; txstringlength)\r\n    {\r\n      txc = txstring&#x5B;txj];\r\n      txj++;\r\n      txstatus=3;\r\n      rtty_txbit (0); \/\/ Start Bit;\r\n      txi=0;\r\n    }\r\n    else \r\n    {\r\n      txstatus=0; \/\/ Should be finished\r\n      txj=0;\r\n    }\r\n    break;\r\n  case 3:\r\n    if(txi&lt;ASCII)\r\n    {\r\n      txi++;\r\n      if (txc &amp; 1) rtty_txbit(1); \r\n      else rtty_txbit(0);\t\r\n      txc = txc &gt;&gt; 1;\r\n      break;\r\n    }\r\n    else \r\n    {\r\n      rtty_txbit (1); \/\/ Stop Bit\r\n      txstatus=4;\r\n      txi=0;\r\n      break;\r\n    } \r\n  case 4:\r\n    if(STOPBITS==2)\r\n    {\r\n      rtty_txbit (1); \/\/ Stop Bit\r\n      txstatus=2;\r\n      break;\r\n    }\r\n    else\r\n    {\r\n      txstatus=2;\r\n      break;\r\n    }\r\n\r\n  }\r\n}\r\n\r\nvoid rtty_txbit (int bit)\r\n{\r\n  if (bit)\r\n  {\r\n    radio1.write(0x73,0x03); \/\/ High\r\n  }\r\n  else\r\n  {\r\n    radio1.write(0x73,0x00); \/\/ Low\r\n  }\r\n}\r\n\r\nvoid setupRadio(){\r\n  pinMode(RFM22B_SDN, OUTPUT);    \/\/ RFM22B SDN is on ARDUINO A3\r\n  digitalWrite(RFM22B_SDN, LOW);\r\n  delay(1000);\r\n  rfm22::initSPI();\r\n  radio1.init();\r\n  radio1.write(0x71, 0x00); \/\/ unmodulated carrier\r\n  \/\/This sets up the GPIOs to automatically switch the antenna depending on Tx or Rx state, only needs to be done at start up\r\n  radio1.write(0x0b,0x12);\r\n  radio1.write(0x0c,0x15);\r\n  radio1.setFrequency(RADIO_FREQUENCY);\r\n  radio1.write(0x6D, 0x04);\/\/ turn tx low power 11db\r\n  radio1.write(0x07, 0x08);\r\n  delay(500);\r\n}\r\n\r\nuint16_t gps_CRC16_checksum (char *string)\r\n{\r\n  size_t i;\r\n  uint16_t crc;\r\n  uint8_t c;\r\n\r\n  crc = 0xFFFF;\r\n\r\n  \/\/ Calculate checksum ignoring the first two $s\r\n  for (i = 5; i &lt; strlen(string); i++)\r\n  {\r\n    c = string&#x5B;i];\r\n    crc = _crc_xmodem_update (crc, c);\r\n  }\r\n\r\n  return crc;\r\n}    \r\nvoid initialise_interrupt() \r\n{\r\n  \/\/ initialize Timer1\r\n  cli();          \/\/ disable global interrupts\r\n  TCCR1A = 0;     \/\/ set entire TCCR1A register to 0\r\n  TCCR1B = 0;     \/\/ same for TCCR1B\r\n  OCR1A = F_CPU \/ 1024 \/ RTTY_BAUD - 1;  \/\/ set compare match register to desired timer count:\r\n  TCCR1B |= (1 &lt;&lt; WGM12);   \/\/ turn on CTC mode:\r\n  \/\/ Set CS10 and CS12 bits for:\r\n  TCCR1B |= (1 &lt;&lt; CS10);\r\n  TCCR1B |= (1 &lt;&lt; CS12);\r\n  \/\/ enable timer compare interrupt:\r\n  TIMSK1 |= (1 &lt;&lt; OCIE1A);\r\n  sei();          \/\/ enable global interrupts\r\n}\r\n\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>One of the things on my\u00a0to-do\u00a0list has been convert the transmission of the RTTY into the background as an interrupt. When the payload is transmitting at 50 baud it effectively sits around doing nothing for 15 seconds whilst it transmits. &hellip;<\/p>\n<p class=\"read-more\"><a href=\"https:\/\/ava.upuaut.net\/?p=408\">Read more &raquo;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-408","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts\/408","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=408"}],"version-history":[{"count":8,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts\/408\/revisions"}],"predecessor-version":[{"id":423,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=\/wp\/v2\/posts\/408\/revisions\/423"}],"wp:attachment":[{"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=408"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=408"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ava.upuaut.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=408"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}