u8x8_nodemcu_hal.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #include <string.h>
  2. #include "rom/ets_sys.h"
  3. #include "driver/gpio.h"
  4. #include "driver/i2c.h"
  5. #include "driver/spi_master.h"
  6. #include "platform.h"
  7. #include "u8x8_nodemcu_hal.h"
  8. #include "esp_heap_alloc_caps.h"
  9. uint8_t u8x8_gpio_and_delay_nodemcu(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  10. {
  11. uint32_t temp;
  12. switch(msg)
  13. {
  14. case U8X8_MSG_GPIO_AND_DELAY_INIT: // called once during init phase of u8g2/u8x8
  15. // can be used to setup pins
  16. for (int idx = 0; idx < U8X8_PIN_OUTPUT_CNT; idx++) {
  17. if (u8x8->pins[idx] != U8X8_PIN_NONE) {
  18. // configure pin as output
  19. gpio_config_t cfg;
  20. memset( (void *)&cfg, 0, sizeof( cfg ) );
  21. cfg.pin_bit_mask = 1ULL << u8x8->pins[idx];
  22. if (idx == U8X8_PIN_I2C_CLOCK || idx == U8X8_PIN_I2C_CLOCK) {
  23. cfg.mode = GPIO_MODE_OUTPUT_OD;
  24. cfg.pull_up_en = GPIO_PULLUP_ENABLE;
  25. } else {
  26. cfg.mode = GPIO_MODE_OUTPUT;
  27. cfg.pull_up_en = GPIO_PULLUP_DISABLE;
  28. }
  29. cfg.pull_down_en = GPIO_PULLDOWN_DISABLE;
  30. cfg.intr_type = GPIO_INTR_DISABLE;
  31. gpio_config( &cfg );
  32. }
  33. }
  34. break;
  35. case U8X8_MSG_DELAY_NANO: // delay arg_int * 1 nano second
  36. ets_delay_us( 1 );
  37. break;
  38. case U8X8_MSG_DELAY_100NANO: // delay arg_int * 100 nano seconds
  39. temp = arg_int * 100;
  40. temp /= 1000;
  41. ets_delay_us( temp > 0 ? temp : 1 );
  42. break;
  43. case U8X8_MSG_DELAY_10MICRO: // delay arg_int * 10 micro seconds
  44. ets_delay_us( arg_int * 10 );
  45. break;
  46. case U8X8_MSG_DELAY_MILLI: // delay arg_int * 1 milli second
  47. ets_delay_us( arg_int * 1000 );
  48. break;
  49. case U8X8_MSG_DELAY_I2C: // arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
  50. temp = 5000 / arg_int; // arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
  51. temp /= 1000;
  52. ets_delay_us( temp > 0 ? temp : 1 );
  53. break;
  54. case U8X8_MSG_GPIO_D0: // D0 or SPI clock pin: Output level in arg_int
  55. //case U8X8_MSG_GPIO_SPI_CLOCK:
  56. break;
  57. case U8X8_MSG_GPIO_D1: // D1 or SPI data pin: Output level in arg_int
  58. //case U8X8_MSG_GPIO_SPI_DATA:
  59. break;
  60. case U8X8_MSG_GPIO_D2: // D2 pin: Output level in arg_int
  61. break;
  62. case U8X8_MSG_GPIO_D3: // D3 pin: Output level in arg_int
  63. break;
  64. case U8X8_MSG_GPIO_D4: // D4 pin: Output level in arg_int
  65. break;
  66. case U8X8_MSG_GPIO_D5: // D5 pin: Output level in arg_int
  67. break;
  68. case U8X8_MSG_GPIO_D6: // D6 pin: Output level in arg_int
  69. break;
  70. case U8X8_MSG_GPIO_D7: // D7 pin: Output level in arg_int
  71. break;
  72. case U8X8_MSG_GPIO_E: // E/WR pin: Output level in arg_int
  73. break;
  74. case U8X8_MSG_GPIO_CS: // CS (chip select) pin: Output level in arg_int
  75. gpio_set_level( u8x8_GetPinValue( u8x8, msg ), arg_int );
  76. break;
  77. case U8X8_MSG_GPIO_DC: // DC (data/cmd, A0, register select) pin: Output level in arg_int
  78. gpio_set_level( u8x8_GetPinValue( u8x8, msg ), arg_int );
  79. break;
  80. case U8X8_MSG_GPIO_RESET: // Reset pin: Output level in arg_int
  81. if (u8x8_GetPinValue( u8x8, msg ) != U8X8_PIN_NONE)
  82. gpio_set_level( u8x8_GetPinValue(u8x8, msg), arg_int );
  83. break;
  84. case U8X8_MSG_GPIO_CS1: // CS1 (chip select) pin: Output level in arg_int
  85. break;
  86. case U8X8_MSG_GPIO_CS2: // CS2 (chip select) pin: Output level in arg_int
  87. break;
  88. case U8X8_MSG_GPIO_I2C_CLOCK: // arg_int=0: Output low at I2C clock pin
  89. // arg_int=1: Input dir with pullup high for I2C clock pin
  90. // for SW comm routine
  91. gpio_set_level( u8x8_GetPinValue( u8x8, msg ), arg_int );
  92. break;
  93. case U8X8_MSG_GPIO_I2C_DATA: // arg_int=0: Output low at I2C data pin
  94. // arg_int=1: Input dir with pullup high for I2C data pin
  95. // for SW comm routine
  96. gpio_set_level( u8x8_GetPinValue( u8x8, msg ), arg_int );
  97. break;
  98. case U8X8_MSG_GPIO_MENU_SELECT:
  99. case U8X8_MSG_GPIO_MENU_NEXT:
  100. case U8X8_MSG_GPIO_MENU_PREV:
  101. case U8X8_MSG_GPIO_MENU_HOME:
  102. u8x8_SetGPIOResult( u8x8, /* get menu select pin state */ 0 );
  103. break;
  104. default:
  105. u8x8_SetGPIOResult( u8x8, 1 ); // default return value
  106. break;
  107. }
  108. return 1;
  109. }
  110. // static variables containing info about the i2c link
  111. // TODO: move to user space in u8x8_t once available
  112. typedef struct {
  113. uint8_t id;
  114. i2c_cmd_handle_t cmd;
  115. struct {
  116. uint8_t *data;
  117. size_t size, used;
  118. } buffer;
  119. } hal_i2c_t;
  120. uint8_t u8x8_byte_nodemcu_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  121. {
  122. uint8_t *data;
  123. hal_i2c_t *hal = ((u8g2_nodemcu_t *)u8x8)->hal;
  124. switch(msg) {
  125. case U8X8_MSG_BYTE_SEND:
  126. if (hal->id == 0) {
  127. data = (uint8_t *)arg_ptr;
  128. while( arg_int > 0 ) {
  129. platform_i2c_send_byte( 0, *data, 0 );
  130. data++;
  131. arg_int--;
  132. }
  133. } else {
  134. while (hal->buffer.size - hal->buffer.used < arg_int) {
  135. hal->buffer.size *= 2;
  136. if (!(hal->buffer.data = (uint8_t *)realloc( hal->buffer.data, hal->buffer.size )))
  137. return 0;
  138. }
  139. memcpy( hal->buffer.data + hal->buffer.used, arg_ptr, arg_int );
  140. hal->buffer.used += arg_int;
  141. }
  142. break;
  143. case U8X8_MSG_BYTE_INIT:
  144. {
  145. // the hal member initially contains the i2c id
  146. int id = (int)hal;
  147. if (!(hal = malloc( sizeof ( hal_i2c_t ) )))
  148. return 0;
  149. hal->id = id;
  150. ((u8g2_nodemcu_t *)u8x8)->hal = hal;
  151. }
  152. break;
  153. case U8X8_MSG_BYTE_SET_DC:
  154. break;
  155. case U8X8_MSG_BYTE_START_TRANSFER:
  156. if (hal->id == 0) {
  157. platform_i2c_send_start( 0 );
  158. platform_i2c_send_address( 0, u8x8_GetI2CAddress(u8x8), PLATFORM_I2C_DIRECTION_TRANSMITTER, 0 );
  159. } else {
  160. hal->buffer.size = 256;
  161. if (!(hal->buffer.data = (uint8_t *)malloc( hal->buffer.size )))
  162. return 0;
  163. hal->buffer.used = 0;
  164. hal->cmd = i2c_cmd_link_create();
  165. i2c_master_start( hal->cmd );
  166. i2c_master_write_byte( hal->cmd, u8x8_GetI2CAddress(u8x8) << 1 | I2C_MASTER_WRITE, false );
  167. }
  168. break;
  169. case U8X8_MSG_BYTE_END_TRANSFER:
  170. if (hal->id == 0) {
  171. platform_i2c_send_stop( 0 );
  172. } else {
  173. if (hal->buffer.used > 0)
  174. i2c_master_write( hal->cmd, hal->buffer.data, hal->buffer.used, false );
  175. i2c_master_stop( hal->cmd );
  176. i2c_master_cmd_begin(hal->id-1, hal->cmd, portMAX_DELAY );
  177. if (hal->buffer.data)
  178. free( hal->buffer.data );
  179. i2c_cmd_link_delete( hal->cmd );
  180. }
  181. break;
  182. default:
  183. return 0;
  184. }
  185. return 1;
  186. }
  187. // static variables containing info about the spi link
  188. // TODO: move to user space in u8x8_t once available
  189. typedef struct {
  190. uint8_t host;
  191. spi_device_handle_t device;
  192. uint8_t last_dc;
  193. struct {
  194. uint8_t *data;
  195. size_t size, used;
  196. } buffer;
  197. } hal_spi_t;
  198. static void flush_buffer_spi( hal_spi_t *hal )
  199. {
  200. if (hal->buffer.used > 0) {
  201. spi_transaction_t trans;
  202. memset( &trans, 0, sizeof( trans ) );
  203. trans.length = hal->buffer.used * 8;
  204. trans.tx_buffer = hal->buffer.data;
  205. spi_device_transmit( hal->device, &trans );
  206. hal->buffer.used = 0;
  207. }
  208. }
  209. uint8_t u8x8_byte_nodemcu_spi(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
  210. {
  211. hal_spi_t *hal = ((u8g2_nodemcu_t *)u8x8)->hal;
  212. switch(msg) {
  213. case U8X8_MSG_BYTE_INIT:
  214. {
  215. /* disable chipselect */
  216. u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
  217. // the hal member initially contains the spi host id
  218. int host = (int)hal;
  219. if (!(hal = malloc( sizeof ( hal_spi_t ) )))
  220. return 0;
  221. hal->host = host;
  222. ((u8g2_nodemcu_t *)u8x8)->hal = hal;
  223. // set up the spi device
  224. spi_device_interface_config_t config;
  225. memset( &config, 0, sizeof( config ) );
  226. config.spics_io_num = -1; // CS is controlled by u8x8 gpio mechanism
  227. config.mode = u8x8_GetSPIClockPhase( u8x8 ) | (u8x8_GetSPIClockPolarity( u8x8 ) << 1);
  228. config.clock_speed_hz = u8x8->display_info->sck_clock_hz;
  229. config.queue_size = 1;
  230. spi_bus_add_device( hal->host, &config, &(hal->device) );
  231. hal->last_dc = 0;
  232. }
  233. break;
  234. case U8X8_MSG_BYTE_SET_DC:
  235. if (hal->last_dc != arg_int)
  236. flush_buffer_spi( hal );
  237. u8x8_gpio_SetDC( u8x8, arg_int );
  238. hal->last_dc = arg_int;
  239. break;
  240. case U8X8_MSG_BYTE_START_TRANSFER:
  241. hal->buffer.size = 256;
  242. if (!(hal->buffer.data = (uint8_t *)pvPortMallocCaps( hal->buffer.size, MALLOC_CAP_DMA )))
  243. return 0;
  244. hal->buffer.used = 0;
  245. u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_enable_level );
  246. break;
  247. case U8X8_MSG_BYTE_SEND:
  248. while (hal->buffer.size - hal->buffer.used < arg_int) {
  249. hal->buffer.size *= 2;
  250. uint8_t *tmp;
  251. if (!(tmp = (uint8_t *)pvPortMallocCaps( hal->buffer.size, MALLOC_CAP_DMA ))) {
  252. free( hal->buffer.data );
  253. return 0;
  254. }
  255. memcpy( tmp, hal->buffer.data, hal->buffer.used );
  256. free( hal->buffer.data );
  257. hal->buffer.data = tmp;
  258. }
  259. memcpy( hal->buffer.data + hal->buffer.used, arg_ptr, arg_int );
  260. hal->buffer.used += arg_int;
  261. break;
  262. case U8X8_MSG_BYTE_END_TRANSFER:
  263. flush_buffer_spi( hal );
  264. u8x8_gpio_SetCS( u8x8, u8x8->display_info->chip_disable_level );
  265. if (hal->buffer.data)
  266. free( hal->buffer.data );
  267. break;
  268. default:
  269. return 0;
  270. }
  271. return 1;
  272. }