u8x8_avr.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #include <util/delay.h>
  2. #include "u8x8_avr.h"
  3. #ifdef AVR_USE_HW_I2C
  4. #include <avr-hw-i2c/i2cmaster.h>
  5. #endif
  6. #ifdef AVR_USE_HW_SPI
  7. #ifndef SCK_DDR
  8. #error "SCK_DDR must be defined externally, eg: -DSCK_DDR=DDRB, for atmega328p."
  9. #endif
  10. #ifndef SCK_BIT
  11. #error "SCK_BIT must be defined externally, eg: -DSCK_BIT=5, for atmega328p."
  12. #endif
  13. #ifndef MOSI_DDR
  14. #error "MOSI_DDR must be defined externally, eg: -DMOSI_DDR=DDRB, for atmega328p."
  15. #endif
  16. #ifndef MOSI_BIT
  17. #error "MOSI_BIT must be defined externally, eg: -DMOSI_BIT=3, for atmega328p."
  18. #endif
  19. #endif
  20. #define P_CPU_NS (1000000000UL / F_CPU)
  21. #ifdef AVR_USE_HW_SPI
  22. uint8_t u8x8_byte_avr_hw_spi (u8x8_t * u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
  23. uint8_t *data;
  24. switch (msg) {
  25. case U8X8_MSG_BYTE_INIT:
  26. SCK_DDR |= _BV (SCK_BIT);
  27. MOSI_DDR |= _BV (MOSI_BIT);
  28. SPCR = (_BV (SPE) | _BV (MSTR));
  29. switch (u8x8->display_info->spi_mode) {
  30. case 0:
  31. break;
  32. case 1:
  33. SPCR |= _BV (CPHA);
  34. break;
  35. case 2:
  36. SPCR |= _BV (CPOL);
  37. break;
  38. case 3:
  39. SPCR |= _BV (CPOL);
  40. SPCR |= _BV (CPHA);
  41. break;
  42. };
  43. switch (F_CPU / u8x8->display_info->sck_clock_hz) {
  44. case 2:
  45. SPSR |= _BV (SPI2X);
  46. break;
  47. case 4:
  48. break;
  49. case 8:
  50. SPSR |= _BV (SPI2X);
  51. SPCR |= _BV (SPR0);
  52. break;
  53. case 16:
  54. SPCR |= _BV (SPR0);
  55. break;
  56. case 32:
  57. SPSR |= _BV (SPI2X);
  58. SPCR |= _BV (SPR1);
  59. break;
  60. case 64:
  61. SPCR |= _BV (SPR1);
  62. break;
  63. case 128:
  64. SPCR |= _BV (SPR1);
  65. SPCR |= _BV (SPR0);
  66. break;
  67. }
  68. u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
  69. break;
  70. case U8X8_MSG_BYTE_SET_DC:
  71. u8x8_gpio_SetDC(u8x8, arg_int);
  72. break;
  73. case U8X8_MSG_BYTE_START_TRANSFER:
  74. u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_enable_level);
  75. u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->post_chip_enable_wait_ns, NULL);
  76. break;
  77. case U8X8_MSG_BYTE_SEND:
  78. data = (uint8_t *) arg_ptr;
  79. while (arg_int > 0) {
  80. SPDR = (uint8_t) * data;
  81. while (!(SPSR & _BV (SPIF)));
  82. data++;
  83. arg_int--;
  84. }
  85. break;
  86. case U8X8_MSG_BYTE_END_TRANSFER:
  87. u8x8->gpio_and_delay_cb(u8x8, U8X8_MSG_DELAY_NANO, u8x8->display_info->pre_chip_disable_wait_ns, NULL);
  88. u8x8_gpio_SetCS(u8x8, u8x8->display_info->chip_disable_level);
  89. break;
  90. default:
  91. return 0;
  92. }
  93. return 1;
  94. }
  95. #endif
  96. #ifdef AVR_USE_HW_I2C
  97. uint8_t u8x8_byte_avr_hw_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  98. {
  99. uint8_t *data;
  100. switch(msg){
  101. case U8X8_MSG_BYTE_SEND:
  102. data = (uint8_t *)arg_ptr;
  103. while( arg_int-- )
  104. i2c_write(*data++);
  105. break;
  106. case U8X8_MSG_BYTE_INIT:
  107. i2c_init();
  108. break;
  109. case U8X8_MSG_BYTE_SET_DC:
  110. /* ignored for i2c */
  111. break;
  112. case U8X8_MSG_BYTE_START_TRANSFER:
  113. i2c_start_wait(u8x8_GetI2CAddress(u8x8)+I2C_WRITE);
  114. break;
  115. case U8X8_MSG_BYTE_END_TRANSFER:
  116. i2c_stop();
  117. break;
  118. default:
  119. return 0;
  120. }
  121. return 1;
  122. }
  123. #endif
  124. uint8_t u8x8_avr_delay (u8x8_t * u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) {
  125. uint8_t cycles;
  126. switch(msg) {
  127. case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
  128. // At 20Mhz, each cycle is 50ns, the call itself is slower.
  129. break;
  130. case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
  131. // Approximate best case values...
  132. #define CALL_CYCLES 26UL
  133. #define CALC_CYCLES 4UL
  134. #define RETURN_CYCLES 4UL
  135. #define CYCLES_PER_LOOP 4UL
  136. cycles = (100UL * arg_int) / (P_CPU_NS * CYCLES_PER_LOOP);
  137. if (cycles > CALL_CYCLES + RETURN_CYCLES + CALC_CYCLES)
  138. break;
  139. __asm__ __volatile__ (
  140. "1: sbiw %0,1" "\n\t" // 2 cycles
  141. "brne 1b":"=w" (cycles):"0" (cycles) // 2 cycles
  142. );
  143. break;
  144. case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
  145. while( arg_int-- ) _delay_us(10);
  146. break;
  147. case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
  148. while( arg_int-- ) _delay_ms(1);
  149. break;
  150. default:
  151. return 0;
  152. }
  153. return 1;
  154. }