hx711.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Module for HX711 load cell amplifier
  2. // https://learn.sparkfun.com/tutorials/load-cell-amplifier-hx711-breakout-hookup-guide
  3. #include "module.h"
  4. #include "lauxlib.h"
  5. #include "lmem.h"
  6. #include "platform.h"
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include "user_interface.h"
  10. static uint8_t data_pin;
  11. static uint8_t clk_pin;
  12. // The fields below are after the pin_num conversion
  13. static uint8_t pin_data_pin;
  14. static uint8_t pin_clk_pin;
  15. #ifdef GPIO_INTERRUPT_ENABLE
  16. static platform_task_handle_t tasknumber;
  17. // HX711_STATUS can be defined to enable the hx711.status() function to get debug info
  18. #undef HX711_STATUS
  19. #define BUFFERS 2
  20. typedef struct {
  21. char *buf[BUFFERS];
  22. uint32_t dropped[BUFFERS];
  23. uint32_t timestamp[BUFFERS];
  24. uint32_t interrupts;
  25. uint32_t hx711_interrupts;
  26. uint16_t buflen;
  27. uint16_t used;
  28. uint32_t nobuffer;
  29. uint8_t active; // slot of the active buffer
  30. uint8_t freed; // slot of the most recently freed buffer
  31. uint8_t mode;
  32. uint8_t dropping; // is non zero when there is no space
  33. int cb_ref;
  34. } CONTROL;
  35. static CONTROL *control;
  36. #endif
  37. /*Lua: hx711.init(clk_pin,data_pin)*/
  38. static int hx711_init(lua_State* L) {
  39. clk_pin = luaL_checkint(L,1);
  40. data_pin = luaL_checkint(L,2);
  41. MOD_CHECK_ID( gpio, clk_pin );
  42. MOD_CHECK_ID( gpio, data_pin );
  43. platform_gpio_mode(clk_pin, PLATFORM_GPIO_OUTPUT, PLATFORM_GPIO_FLOAT);
  44. platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT);
  45. platform_gpio_write(clk_pin,1);//put chip to sleep.
  46. pin_data_pin = pin_num[data_pin];
  47. pin_clk_pin = pin_num[clk_pin];
  48. return 0;
  49. }
  50. static int32_t ICACHE_RAM_ATTR read_sample(char mode) {
  51. int i;
  52. int32_t data = 0;
  53. for (i = 0; i < 24 ; i++){ //clock in the 24 bits
  54. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin);
  55. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin);
  56. data = data << 1;
  57. if (GPIO_REG_READ(GPIO_IN_ADDRESS) & (1 << pin_data_pin)) {
  58. data = i == 0 ? -1 : data | 1; //signextend the first bit
  59. }
  60. }
  61. //add 25th-27th clock pulse to prevent protocol error
  62. for (i = 0; i <= mode; i++) {
  63. GPIO_REG_WRITE(GPIO_OUT_W1TS_ADDRESS, 1 << pin_clk_pin);
  64. GPIO_REG_WRITE(GPIO_OUT_W1TC_ADDRESS, 1 << pin_clk_pin);
  65. }
  66. return data;
  67. }
  68. #ifdef GPIO_INTERRUPT_ENABLE
  69. static void ICACHE_RAM_ATTR hx711_data_available() {
  70. if (!control) {
  71. return;
  72. }
  73. uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS);
  74. if (bits & (1 << pin_data_pin)) {
  75. return; // not ready
  76. }
  77. // Read a sample
  78. int32_t data = read_sample(control->mode);
  79. if (control->dropping) {
  80. if (control->active == control->freed) {
  81. // still can't advance
  82. control->nobuffer++;
  83. return;
  84. }
  85. // Advance
  86. control->active = (1 + control->active) % BUFFERS;
  87. control->dropping = 0;
  88. }
  89. // insert into the active buffer
  90. char *dest = control->buf[control->active] + control->used;
  91. *dest++ = data;
  92. *dest++ = data >> 8;
  93. *dest++ = data >> 16;
  94. control->used += 3;
  95. if (control->used == control->buflen) {
  96. control->used = 0;
  97. control->timestamp[control->active] = system_get_time();
  98. control->dropped[control->active] = control->nobuffer;
  99. control->nobuffer = 0;
  100. // post task
  101. platform_post_medium(tasknumber, control->active);
  102. uint8_t next_active = (1 + control->active) % BUFFERS;
  103. if (control->active == control->freed) {
  104. // We can't advance to the buffer
  105. control->dropping = 1;
  106. } else {
  107. // flip to other buffer
  108. control->active = next_active;
  109. }
  110. }
  111. }
  112. static uint32_t ICACHE_RAM_ATTR hx711_interrupt(uint32_t ret_gpio_status)
  113. {
  114. // This function really is running at interrupt level with everything
  115. // else masked off. It should take as little time as necessary.
  116. //
  117. //
  118. // This gets the set of pins which have changed status
  119. uint32 gpio_status = GPIO_REG_READ(GPIO_STATUS_ADDRESS);
  120. int pin_mask = 1 << pin_data_pin;
  121. int i;
  122. control->interrupts++;
  123. if (gpio_status & pin_mask) {
  124. uint32_t bits = GPIO_REG_READ(GPIO_IN_ADDRESS);
  125. control->hx711_interrupts++;
  126. if (!(bits & pin_mask)) {
  127. // is now ready to read
  128. hx711_data_available();
  129. }
  130. GPIO_REG_WRITE(GPIO_STATUS_W1TC_ADDRESS, gpio_status & pin_mask);
  131. }
  132. return gpio_status & ~pin_mask;
  133. }
  134. // Lua: hx711.start( mode, samples, callback )
  135. static int hx711_start( lua_State* L )
  136. {
  137. uint32_t mode = luaL_checkint( L, 1 );
  138. uint32_t samples = luaL_checkint( L, 2 );
  139. if (mode > 2) {
  140. return luaL_argerror( L, 1, "Mode value out of range" );
  141. }
  142. if (!samples || samples > 400) {
  143. return luaL_argerror( L, 2, "Samples value out of range (1-400)" );
  144. }
  145. if (control) {
  146. return luaL_error( L, "Already running" );
  147. }
  148. int buflen = 3 * samples;
  149. control = (CONTROL *) luaM_malloc(L, sizeof(CONTROL) + BUFFERS * buflen);
  150. if (!control) {
  151. return luaL_error( L, "Failed to allocate memory" );
  152. }
  153. int cb_ref;
  154. if (lua_type(L, 3) == LUA_TFUNCTION) {
  155. lua_pushvalue(L, 3); // copy argument (func) to the top of stack
  156. cb_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  157. } else {
  158. luaM_free(L, control);
  159. control = NULL;
  160. return luaL_argerror( L, 3, "Not a callback function" );
  161. }
  162. memset(control, 0, sizeof(*control));
  163. control->buf[0] = (char *) (control + 1);
  164. control->buflen = buflen;
  165. int i;
  166. for (i = 1; i < BUFFERS; i++) {
  167. control->buf[i] = control->buf[i - 1] + buflen;
  168. }
  169. control->mode = mode;
  170. control->cb_ref = cb_ref;
  171. control->freed = BUFFERS - 1;
  172. // configure data_pin as interrupt input
  173. platform_gpio_register_intr_hook(1 << pin_data_pin, hx711_interrupt);
  174. platform_gpio_mode(data_pin, PLATFORM_GPIO_INT, PLATFORM_GPIO_FLOAT);
  175. platform_gpio_intr_init(data_pin, GPIO_PIN_INTR_NEGEDGE);
  176. // Wake up chip
  177. platform_gpio_write(clk_pin, 0);
  178. return 0;
  179. }
  180. // Lua: hx711.stop( )
  181. static int hx711_stop( lua_State* L )
  182. {
  183. if (control) {
  184. platform_gpio_mode(data_pin, PLATFORM_GPIO_INPUT, PLATFORM_GPIO_FLOAT);
  185. CONTROL *to_free = control;
  186. control = NULL;
  187. luaL_unref(L, LUA_REGISTRYINDEX, to_free->cb_ref);
  188. luaM_free(L, to_free);
  189. }
  190. return 0;
  191. }
  192. static int hx711_status( lua_State* L )
  193. {
  194. if (control) {
  195. lua_pushlstring(L, (char *) control, sizeof(*control));
  196. return 1;
  197. }
  198. return 0;
  199. }
  200. static void hx711_task(platform_task_param_t param, uint8_t prio)
  201. {
  202. (void) prio;
  203. if (!control) {
  204. return;
  205. }
  206. lua_State *L = lua_getstate();
  207. if (control->cb_ref != LUA_NOREF) {
  208. lua_rawgeti(L, LUA_REGISTRYINDEX, control->cb_ref);
  209. lua_pushlstring(L, control->buf[param], control->buflen);
  210. lua_pushinteger(L, control->timestamp[param]);
  211. lua_pushinteger(L, control->dropped[param]);
  212. control->freed = param;
  213. luaL_pcallx(L, 3, 0);
  214. }
  215. }
  216. #endif
  217. #define HX711_MAX_WAIT 1000000
  218. /*will only read chA@128gain*/
  219. /*Lua: result = hx711.read()*/
  220. static int hx711_read(lua_State* L) {
  221. int j;
  222. //TODO: double check init has happened first.
  223. //
  224. uint32_t mode = luaL_optinteger(L, 1, 0);
  225. if (mode > 2) {
  226. return luaL_argerror( L, 1, "Mode value out of range" );
  227. }
  228. #ifdef GPIO_INTERRUPT_ENABLE
  229. if (control) {
  230. hx711_stop(L);
  231. }
  232. #endif
  233. //wakeup hx711
  234. platform_gpio_write(clk_pin, 0);
  235. int32_t data;
  236. // read two samples if mode > 0. We discard the first read and return the
  237. // second value.
  238. for (j = (mode ? 1 : 0); j >= 0; j--) {
  239. uint32_t i;
  240. //wait for data ready. or time out.
  241. system_soft_wdt_feed(); //clear WDT... this may take a while.
  242. for (i = 0; i<HX711_MAX_WAIT && platform_gpio_read(data_pin)==1;i++){
  243. asm ("nop");
  244. }
  245. //Handle timeout error
  246. if (i >= HX711_MAX_WAIT) {
  247. return luaL_error( L, "ADC timeout!");
  248. }
  249. data = read_sample(mode);
  250. }
  251. //sleep -- unfortunately, this resets the mode to 0
  252. platform_gpio_write(clk_pin, 1);
  253. lua_pushinteger(L, data);
  254. return 1;
  255. }
  256. // Module function map
  257. LROT_BEGIN(hx711, NULL, 0)
  258. LROT_FUNCENTRY( init, hx711_init )
  259. LROT_FUNCENTRY( read, hx711_read )
  260. #ifdef GPIO_INTERRUPT_ENABLE
  261. LROT_FUNCENTRY( start, hx711_start )
  262. #ifdef HX711_STATUS
  263. LROT_FUNCENTRY( status, hx711_status )
  264. #endif
  265. LROT_FUNCENTRY( stop, hx711_stop )
  266. #endif
  267. LROT_END(hx711, NULL, 0)
  268. int luaopen_hx711(lua_State *L) {
  269. #ifdef GPIO_INTERRUPT_ENABLE
  270. tasknumber = platform_task_get_id(hx711_task);
  271. #endif
  272. return 0;
  273. }
  274. NODEMCU_MODULE(HX711, "hx711", hx711, luaopen_hx711);