serial.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. /*
  2. * WARNING: be careful changing this code, it is very timing dependent
  3. */
  4. #ifndef F_CPU
  5. #define F_CPU 16000000
  6. #endif
  7. #include <avr/io.h>
  8. #include <avr/interrupt.h>
  9. #include <util/delay.h>
  10. #include <stdbool.h>
  11. #include "serial.h"
  12. #ifdef USE_SERIAL
  13. #define _delay_sub_us(x) __builtin_avr_delay_cycles(x)
  14. // Serial pulse period in microseconds.
  15. #define SELECT_SERIAL_SPEED 1
  16. #if SELECT_SERIAL_SPEED == 0
  17. // Very High speed
  18. #define SERIAL_DELAY 4 // micro sec
  19. #define READ_WRITE_START_ADJUST 30 // cycles
  20. #define READ_WRITE_WIDTH_ADJUST 10 // cycles
  21. #elif SELECT_SERIAL_SPEED == 1
  22. // High speed
  23. #define SERIAL_DELAY 6 // micro sec
  24. #define READ_WRITE_START_ADJUST 23 // cycles
  25. #define READ_WRITE_WIDTH_ADJUST 10 // cycles
  26. #elif SELECT_SERIAL_SPEED == 2
  27. // Middle speed
  28. #define SERIAL_DELAY 12 // micro sec
  29. #define READ_WRITE_START_ADJUST 25 // cycles
  30. #define READ_WRITE_WIDTH_ADJUST 10 // cycles
  31. #elif SELECT_SERIAL_SPEED == 3
  32. // Low speed
  33. #define SERIAL_DELAY 24 // micro sec
  34. #define READ_WRITE_START_ADJUST 25 // cycles
  35. #define READ_WRITE_WIDTH_ADJUST 10 // cycles
  36. #elif SELECT_SERIAL_SPEED == 4
  37. // Very Low speed
  38. #define SERIAL_DELAY 50 // micro sec
  39. #define READ_WRITE_START_ADJUST 25 // cycles
  40. #define READ_WRITE_WIDTH_ADJUST 10 // cycles
  41. #else
  42. #error Illegal Serial Speed
  43. #endif
  44. #define SERIAL_DELAY_HALF1 (SERIAL_DELAY/2)
  45. #define SERIAL_DELAY_HALF2 (SERIAL_DELAY - SERIAL_DELAY/2)
  46. #define SLAVE_INT_WIDTH 1
  47. #define SLAVE_INT_RESPONSE_TIME SERIAL_DELAY
  48. uint8_t volatile serial_slave_buffer[SERIAL_SLAVE_BUFFER_LENGTH] = {0};
  49. uint8_t volatile serial_master_buffer[SERIAL_MASTER_BUFFER_LENGTH] = {0};
  50. #define SLAVE_DATA_CORRUPT (1<<0)
  51. volatile uint8_t status = 0;
  52. inline static
  53. void serial_delay(void) {
  54. _delay_us(SERIAL_DELAY);
  55. }
  56. inline static
  57. void serial_delay_half1(void) {
  58. _delay_us(SERIAL_DELAY_HALF1);
  59. }
  60. inline static
  61. void serial_delay_half2(void) {
  62. _delay_us(SERIAL_DELAY_HALF2);
  63. }
  64. inline static
  65. void serial_output(void) {
  66. SERIAL_PIN_DDR |= SERIAL_PIN_MASK;
  67. }
  68. // make the serial pin an input with pull-up resistor
  69. inline static
  70. void serial_input_with_pullup(void) {
  71. SERIAL_PIN_DDR &= ~SERIAL_PIN_MASK;
  72. SERIAL_PIN_PORT |= SERIAL_PIN_MASK;
  73. }
  74. inline static
  75. uint8_t serial_read_pin(void) {
  76. return !!(SERIAL_PIN_INPUT & SERIAL_PIN_MASK);
  77. }
  78. inline static
  79. void serial_low(void) {
  80. SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK;
  81. }
  82. inline static
  83. void serial_high(void) {
  84. SERIAL_PIN_PORT |= SERIAL_PIN_MASK;
  85. }
  86. void serial_master_init(void) {
  87. serial_output();
  88. serial_high();
  89. }
  90. void serial_slave_init(void) {
  91. serial_input_with_pullup();
  92. #ifndef USE_SERIAL_PD2
  93. // Enable INT0
  94. EIMSK |= _BV(INT0);
  95. // Trigger on falling edge of INT0
  96. EICRA &= ~(_BV(ISC00) | _BV(ISC01));
  97. #else
  98. // Enable INT2
  99. EIMSK |= _BV(INT2);
  100. // Trigger on falling edge of INT2
  101. EICRA &= ~(_BV(ISC20) | _BV(ISC21));
  102. #endif
  103. }
  104. // Used by the sender to synchronize timing with the reciver.
  105. static
  106. void sync_recv(void) {
  107. for (int i = 0; i < SERIAL_DELAY*5 && serial_read_pin(); i++ ) {
  108. }
  109. // This shouldn't hang if the slave disconnects because the
  110. // serial line will float to high if the slave does disconnect.
  111. while (!serial_read_pin());
  112. }
  113. // Used by the reciver to send a synchronization signal to the sender.
  114. static
  115. void sync_send(void) {
  116. serial_low();
  117. serial_delay();
  118. serial_high();
  119. }
  120. // Reads a byte from the serial line
  121. static
  122. uint8_t serial_read_byte(void) {
  123. uint8_t byte = 0;
  124. _delay_sub_us(READ_WRITE_START_ADJUST);
  125. for ( uint8_t i = 0; i < 8; ++i) {
  126. serial_delay_half1(); // read the middle of pulses
  127. byte = (byte << 1) | serial_read_pin();
  128. _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
  129. serial_delay_half2();
  130. }
  131. return byte;
  132. }
  133. // Sends a byte with MSB ordering
  134. static
  135. void serial_write_byte(uint8_t data) {
  136. uint8_t b = 1<<7;
  137. while( b ) {
  138. if(data & b) {
  139. serial_high();
  140. } else {
  141. serial_low();
  142. }
  143. b >>= 1;
  144. serial_delay();
  145. }
  146. serial_low(); // sync_send() / senc_recv() need raise edge
  147. }
  148. // interrupt handle to be used by the slave device
  149. ISR(SERIAL_PIN_INTERRUPT) {
  150. serial_output();
  151. // slave send phase
  152. uint8_t checksum = 0;
  153. for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) {
  154. sync_send();
  155. serial_write_byte(serial_slave_buffer[i]);
  156. checksum += serial_slave_buffer[i];
  157. }
  158. sync_send();
  159. serial_write_byte(checksum);
  160. // slave switch to input
  161. sync_send(); //0
  162. serial_delay_half1(); //1
  163. serial_low(); //2
  164. serial_input_with_pullup(); //2
  165. serial_delay_half1(); //3
  166. // slave recive phase
  167. uint8_t checksum_computed = 0;
  168. for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) {
  169. sync_recv();
  170. serial_master_buffer[i] = serial_read_byte();
  171. checksum_computed += serial_master_buffer[i];
  172. }
  173. sync_recv();
  174. uint8_t checksum_received = serial_read_byte();
  175. if ( checksum_computed != checksum_received ) {
  176. status |= SLAVE_DATA_CORRUPT;
  177. } else {
  178. status &= ~SLAVE_DATA_CORRUPT;
  179. }
  180. sync_recv(); //weit master output to high
  181. }
  182. inline
  183. bool serial_slave_DATA_CORRUPT(void) {
  184. return status & SLAVE_DATA_CORRUPT;
  185. }
  186. // Copies the serial_slave_buffer to the master and sends the
  187. // serial_master_buffer to the slave.
  188. //
  189. // Returns:
  190. // 0 => no error
  191. // 1 => slave did not respond
  192. // 2 => checksum error
  193. int serial_update_buffers(void) {
  194. // this code is very time dependent, so we need to disable interrupts
  195. cli();
  196. // signal to the slave that we want to start a transaction
  197. serial_output();
  198. serial_low();
  199. _delay_us(SLAVE_INT_WIDTH);
  200. // wait for the slaves response
  201. serial_input_with_pullup();
  202. _delay_us(SLAVE_INT_RESPONSE_TIME);
  203. // check if the slave is present
  204. if (serial_read_pin()) {
  205. // slave failed to pull the line low, assume not present
  206. serial_output();
  207. serial_high();
  208. sei();
  209. return 1;
  210. }
  211. // master recive phase
  212. // if the slave is present syncronize with it
  213. uint8_t checksum_computed = 0;
  214. // receive data from the slave
  215. for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) {
  216. sync_recv();
  217. serial_slave_buffer[i] = serial_read_byte();
  218. checksum_computed += serial_slave_buffer[i];
  219. }
  220. sync_recv();
  221. uint8_t checksum_received = serial_read_byte();
  222. if (checksum_computed != checksum_received) {
  223. serial_output();
  224. serial_high();
  225. sei();
  226. return 2;
  227. }
  228. // master switch to output
  229. sync_recv(); //0
  230. serial_delay(); //1
  231. serial_low(); //3
  232. serial_output(); // 3
  233. serial_delay_half1(); //4
  234. // master send phase
  235. uint8_t checksum = 0;
  236. for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) {
  237. sync_send();
  238. serial_write_byte(serial_master_buffer[i]);
  239. checksum += serial_master_buffer[i];
  240. }
  241. sync_send();
  242. serial_write_byte(checksum);
  243. // always, release the line when not in use
  244. sync_send();
  245. sei();
  246. return 0;
  247. }
  248. #endif