You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

288 lines
6.6 KiB

  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. // Enable INT3
  93. EIMSK |= _BV(INT3);
  94. // Trigger on falling edge of INT3
  95. EICRA &= ~(_BV(ISC30) | _BV(ISC31));
  96. }
  97. // Used by the sender to synchronize timing with the reciver.
  98. static
  99. void sync_recv(void) {
  100. for (int i = 0; i < SERIAL_DELAY*5 && serial_read_pin(); i++ ) {
  101. }
  102. // This shouldn't hang if the slave disconnects because the
  103. // serial line will float to high if the slave does disconnect.
  104. while (!serial_read_pin());
  105. }
  106. // Used by the reciver to send a synchronization signal to the sender.
  107. static
  108. void sync_send(void) {
  109. serial_low();
  110. serial_delay();
  111. serial_high();
  112. }
  113. // Reads a byte from the serial line
  114. static
  115. uint8_t serial_read_byte(void) {
  116. uint8_t byte = 0;
  117. _delay_sub_us(READ_WRITE_START_ADJUST);
  118. for ( uint8_t i = 0; i < 8; ++i) {
  119. serial_delay_half1(); // read the middle of pulses
  120. byte = (byte << 1) | serial_read_pin();
  121. _delay_sub_us(READ_WRITE_WIDTH_ADJUST);
  122. serial_delay_half2();
  123. }
  124. return byte;
  125. }
  126. // Sends a byte with MSB ordering
  127. static
  128. void serial_write_byte(uint8_t data) {
  129. uint8_t b = 1<<7;
  130. while( b ) {
  131. if(data & b) {
  132. serial_high();
  133. } else {
  134. serial_low();
  135. }
  136. b >>= 1;
  137. serial_delay();
  138. }
  139. serial_low(); // sync_send() / senc_recv() need raise edge
  140. }
  141. // interrupt handle to be used by the slave device
  142. ISR(SERIAL_PIN_INTERRUPT) {
  143. serial_output();
  144. // slave send phase
  145. uint8_t checksum = 0;
  146. for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) {
  147. sync_send();
  148. serial_write_byte(serial_slave_buffer[i]);
  149. checksum += serial_slave_buffer[i];
  150. }
  151. sync_send();
  152. serial_write_byte(checksum);
  153. // slave switch to input
  154. sync_send(); //0
  155. serial_delay_half1(); //1
  156. serial_low(); //2
  157. serial_input_with_pullup(); //2
  158. serial_delay_half1(); //3
  159. // slave recive phase
  160. uint8_t checksum_computed = 0;
  161. for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) {
  162. sync_recv();
  163. serial_master_buffer[i] = serial_read_byte();
  164. checksum_computed += serial_master_buffer[i];
  165. }
  166. sync_recv();
  167. uint8_t checksum_received = serial_read_byte();
  168. if ( checksum_computed != checksum_received ) {
  169. status |= SLAVE_DATA_CORRUPT;
  170. } else {
  171. status &= ~SLAVE_DATA_CORRUPT;
  172. }
  173. sync_recv(); //weit master output to high
  174. }
  175. inline
  176. bool serial_slave_DATA_CORRUPT(void) {
  177. return status & SLAVE_DATA_CORRUPT;
  178. }
  179. // Copies the serial_slave_buffer to the master and sends the
  180. // serial_master_buffer to the slave.
  181. //
  182. // Returns:
  183. // 0 => no error
  184. // 1 => slave did not respond
  185. // 2 => checksum error
  186. int serial_update_buffers(void) {
  187. // this code is very time dependent, so we need to disable interrupts
  188. cli();
  189. // signal to the slave that we want to start a transaction
  190. serial_output();
  191. serial_low();
  192. _delay_us(SLAVE_INT_WIDTH);
  193. // wait for the slaves response
  194. serial_input_with_pullup();
  195. _delay_us(SLAVE_INT_RESPONSE_TIME);
  196. // check if the slave is present
  197. if (serial_read_pin()) {
  198. // slave failed to pull the line low, assume not present
  199. serial_output();
  200. serial_high();
  201. sei();
  202. return 1;
  203. }
  204. // master recive phase
  205. // if the slave is present syncronize with it
  206. uint8_t checksum_computed = 0;
  207. // receive data from the slave
  208. for (int i = 0; i < SERIAL_SLAVE_BUFFER_LENGTH; ++i) {
  209. sync_recv();
  210. serial_slave_buffer[i] = serial_read_byte();
  211. checksum_computed += serial_slave_buffer[i];
  212. }
  213. sync_recv();
  214. uint8_t checksum_received = serial_read_byte();
  215. if (checksum_computed != checksum_received) {
  216. serial_output();
  217. serial_high();
  218. sei();
  219. return 2;
  220. }
  221. // master switch to output
  222. sync_recv(); //0
  223. serial_delay(); //1
  224. serial_low(); //3
  225. serial_output(); // 3
  226. serial_delay_half1(); //4
  227. // master send phase
  228. uint8_t checksum = 0;
  229. for (int i = 0; i < SERIAL_MASTER_BUFFER_LENGTH; ++i) {
  230. sync_send();
  231. serial_write_byte(serial_master_buffer[i]);
  232. checksum += serial_master_buffer[i];
  233. }
  234. sync_send();
  235. serial_write_byte(checksum);
  236. // always, release the line when not in use
  237. sync_send();
  238. sei();
  239. return 0;
  240. }
  241. #endif