ssd1306.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808
  1. #include "ssd1306.h"
  2. #include "settings.h"
  3. #include "buzzer.h"
  4. #include "iron.h"
  5. #include "gui.h"
  6. oled_t oled = {
  7. .ptr = &oled.buffer[0]
  8. };
  9. static uint8_t lastContrast;
  10. // Silicon bug workaround for STM32F103 as ST document ES093 rev 7
  11. /*
  12. __HAL_I2C_DISABLE(device);
  13. HW_SCL_GPIO_Port->ODR |= HW_SCL_Pin;
  14. HW_SDA_GPIO_Port->ODR |= HW_SDA_Pin;
  15. GPIO_InitTypeDef GPIO_InitStruct = {0};
  16. GPIO_InitStruct.Pin = SW_SCL_Pin;
  17. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  18. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  19. HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
  20. GPIO_InitStruct.Pin = SW_SDA_Pin;
  21. HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
  22. // SCL, SDA HIGH
  23. while( !(HW_SDA_GPIO_Port->IDR & HW_SDA_Pin) || !(HW_SCL_GPIO_Port->IDR & HW_SCL_Pin) );
  24. // SDA LOW
  25. HW_SDA_GPIO_Port->ODR &= ~(HW_SDA_Pin);
  26. while(HW_SDA_GPIO_Port->IDR & HW_SDA_Pin);
  27. // SCL LOW
  28. HW_SCL_GPIO_Port->ODR &= ~(HW_SCL_Pin);
  29. while(HW_SCL_GPIO_Port->IDR & HW_SCL_Pin);
  30. // SCL HIGH
  31. HW_SCL_GPIO_Port->ODR |= HW_SCL_Pin;
  32. while(!(HW_SCL_GPIO_Port->IDR & HW_SCL_Pin));
  33. // SDA HIGH
  34. HW_SDA_GPIO_Port->ODR |= HW_SDA_Pin;
  35. while(!(HW_SDA_GPIO_Port->IDR & HW_SDA_Pin));
  36. GPIO_InitStruct.Pin = SW_SCL_Pin;
  37. GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  38. HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
  39. GPIO_InitStruct.Pin = SW_SDA_Pin;
  40. HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
  41. device->Instance->CR1 |= I2C_CR1_SWRST;
  42. device->Instance->CR1 &= ~(I2C_CR1_SWRST);
  43. __HAL_I2C_ENABLE(device);
  44. */
  45. #if defined OLED_I2C && defined OLED_DEVICE
  46. // Silicon bug workaround for STM32F103, force I2C RCC reset and re-init
  47. void i2c_workaround(void){
  48. __HAL_RCC_I2C1_FORCE_RESET();
  49. __HAL_RCC_I2C2_FORCE_RESET();
  50. HAL_Delay(10);
  51. __HAL_RCC_I2C1_RELEASE_RESET();
  52. __HAL_RCC_I2C2_RELEASE_RESET();
  53. oled.device->State = HAL_I2C_STATE_RESET;
  54. __HAL_RCC_DMA1_CLK_ENABLE();
  55. oled.device->Instance = I2C1;
  56. oled.device->Init.ClockSpeed = 400000;
  57. oled.device->Init.DutyCycle = I2C_DUTYCYCLE_2;
  58. oled.device->Init.OwnAddress1 = 0;
  59. oled.device->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  60. oled.device->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  61. oled.device->Init.OwnAddress2 = 0;
  62. oled.device->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  63. oled.device->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  64. if (HAL_I2C_Init(oled.device) != HAL_OK){
  65. Error_Handler();
  66. }
  67. }
  68. #endif
  69. #if (defined OLED_SPI && !defined OLED_DEVICE) || (defined OLED_I2C && (!defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW)))
  70. void enable_soft_Oled(void){
  71. GPIO_InitTypeDef GPIO_InitStruct = {0};
  72. #if defined HW_SCL_Pin && defined HW_SDA_Pin
  73. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  74. GPIO_InitStruct.Pull = GPIO_NOPULL;
  75. /*Configure GPIO pins : SDA_Pin */
  76. GPIO_InitStruct.Pin = HW_SDA_Pin;
  77. HAL_GPIO_Init(HW_SDA_GPIO_Port, &GPIO_InitStruct);
  78. /*Configure GPIO pins : SDA_Pin */
  79. GPIO_InitStruct.Pin = HW_SCL_Pin;
  80. HAL_GPIO_Init(HW_SCL_GPIO_Port, &GPIO_InitStruct);
  81. #endif
  82. #if defined SW_SDA_Pin && defined SW_SCL_Pin
  83. Oled_Set_SDA();
  84. Oled_Set_SCL();
  85. #ifdef OLED_I2C
  86. GPIO_InitStruct.Pull = GPIO_PULLUP;
  87. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
  88. #else
  89. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  90. #endif
  91. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  92. /*Configure GPIO pins : SCL_Pin */
  93. GPIO_InitStruct.Pin = SW_SCL_Pin;
  94. HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
  95. /*Configure GPIO pins : SDA_Pin */
  96. GPIO_InitStruct.Pin = SW_SDA_Pin;
  97. HAL_GPIO_Init(SW_SDA_GPIO_Port, &GPIO_InitStruct);
  98. #endif
  99. #ifdef OLED_I2C
  100. // Reset the bus
  101. i2cStart();
  102. Oled_Set_SDA();
  103. for(uint8_t c=0;c<9;c++){
  104. Oled_Set_SCL();
  105. i2cDelay();
  106. Oled_Clear_SCL();
  107. i2cDelay();
  108. }
  109. i2cStop();
  110. #endif
  111. }
  112. void disable_soft_Oled(void){
  113. GPIO_InitTypeDef GPIO_InitStruct = {0};
  114. #if defined SW_SCL_Pin && defined SW_SDA_Pin
  115. GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
  116. GPIO_InitStruct.Pull = GPIO_NOPULL;
  117. GPIO_InitStruct.Pin = SW_SCL_Pin;
  118. HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
  119. GPIO_InitStruct.Pin = SW_SDA_Pin;
  120. HAL_GPIO_Init(SW_SDA_GPIO_Port, &GPIO_InitStruct);
  121. #endif
  122. #if defined HW_SCL_Pin && defined HW_SDA_PIN
  123. GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
  124. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  125. GPIO_InitStruct.Pin = HW_SDA_Pin;
  126. HAL_GPIO_Init(HW_SDA_GPIO_Port, &GPIO_InitStruct);
  127. GPIO_InitStruct.Pin = HW_SCL_Pin;
  128. HAL_GPIO_Init(HW_SCL_GPIO_Port, &GPIO_InitStruct);
  129. #endif
  130. }
  131. #endif
  132. #if defined OLED_SPI && !defined OLED_DEVICE
  133. void spi_send(uint8_t* bf, uint16_t count){
  134. uint8_t shift,data;
  135. while(count--){
  136. data = *bf++;
  137. if((data==0) || (data==0xFF)){
  138. if(data==0)
  139. Oled_Clear_SDA();
  140. else
  141. Oled_Set_SDA();
  142. // Much faster without a loop!
  143. Oled_Set_SCL();
  144. Oled_Clear_SCL();
  145. Oled_Set_SCL();
  146. Oled_Clear_SCL();
  147. Oled_Set_SCL();
  148. Oled_Clear_SCL();
  149. Oled_Set_SCL();
  150. Oled_Clear_SCL();
  151. Oled_Set_SCL();
  152. Oled_Clear_SCL();
  153. Oled_Set_SCL();
  154. Oled_Clear_SCL();
  155. Oled_Set_SCL();
  156. Oled_Clear_SCL();
  157. Oled_Set_SCL();
  158. Oled_Clear_SCL();
  159. }
  160. else{
  161. for(shift = 0; shift < 8; shift++){
  162. if(data & 0x80){
  163. Oled_Set_SDA();
  164. }
  165. else{
  166. Oled_Clear_SDA();
  167. }
  168. Oled_Set_SCL();
  169. data <<= 1;
  170. Oled_Clear_SCL();
  171. }
  172. }
  173. }
  174. }
  175. #endif
  176. #if defined OLED_I2C && (!defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW))
  177. void i2cDelay(void){
  178. asm( "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n\
  179. nop\nnop\nnop\nnop\nnop\nnop\nnop/*\nnop\n\
  180. nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop*/");
  181. }
  182. void i2cStart(void){ // Start condition, SDA transition to low with SCL high
  183. Oled_Set_SCL();
  184. i2cDelay();
  185. Oled_Clear_SDA();
  186. i2cDelay();
  187. Oled_Clear_SCL();
  188. i2cDelay();
  189. }
  190. void i2cStop(void){ // Stop condition, SCL transition to high with SDA low
  191. Oled_Clear_SDA();
  192. i2cDelay();
  193. Oled_Set_SCL();
  194. i2cDelay();
  195. Oled_Set_SDA();
  196. i2cDelay();
  197. }
  198. // This sw i2c driver is extremely timing optimized, done specially for ksger v2.1 and compatibles running at 36MHz.
  199. // Hacks clock low time using the slow rise time (i2c pullup resistors) as the delay.
  200. // Will start failing if the core runs faster than 44-48MHz because of the tight timing.
  201. void i2cBegin(uint8_t mode){
  202. uint8_t bytes, shift, data[2]= { OLED_ADDRESS, mode };
  203. uint8_t *bf=data;
  204. bytes=1;
  205. do{
  206. shift=7;
  207. do{
  208. SW_SDA_GPIO_Port->BSRR = SW_SDA_Pin<<(16*!(*bf & (1<<shift)));
  209. Oled_Set_SCL();
  210. i2cDelay();
  211. Oled_Clear_SCL();
  212. }while(shift--);
  213. i2cDelay();
  214. Oled_Set_SCL();
  215. i2cDelay();
  216. //Oled_Set_SDA(); // As we don't care about the ACK, don't release SDA
  217. //i2cDelay();
  218. //Get ACK here
  219. Oled_Clear_SCL();
  220. bf++;
  221. }while(bytes--);
  222. }
  223. void i2cSend(uint8_t* bf, uint16_t count, uint8_t mode){
  224. uint8_t shift;
  225. i2cStart();
  226. i2cBegin(mode);
  227. while(count--){
  228. shift=7;
  229. if( (*bf==0)||(*bf==0xFF)){ // If data 0 or 0xff, we don't have to toggle data line, send the data fast
  230. SW_SDA_GPIO_Port->BSRR = SW_SDA_Pin<<(16*(*bf==0));
  231. do{
  232. Oled_Set_SCL();
  233. i2cDelay();
  234. Oled_Clear_SCL();
  235. }while(shift--);
  236. }
  237. else{
  238. do{
  239. SW_SDA_GPIO_Port->BSRR = SW_SDA_Pin<<(16*!(*bf & (1<<shift)));
  240. Oled_Set_SCL();
  241. i2cDelay();
  242. Oled_Clear_SCL();
  243. }while(shift--);
  244. }
  245. i2cDelay();
  246. Oled_Set_SCL();
  247. i2cDelay();
  248. //Oled_Set_SDA(); // As we don't care about the ACK, don't release SDA
  249. //i2cDelay();
  250. //Get ACK here
  251. Oled_Clear_SCL();
  252. bf++;
  253. }
  254. i2cStop();
  255. }
  256. #endif
  257. // Send command in blocking mode
  258. void write_cmd(uint8_t cmd) {
  259. while(oled.status==oled_busy); // Wait for DMA to finish
  260. #if defined OLED_SPI
  261. #ifdef USE_CS
  262. Oled_Clear_CS();
  263. #endif
  264. #ifdef USE_DC
  265. Oled_Clear_DC();
  266. #endif
  267. #ifdef OLED_DEVICE
  268. HAL_StatusTypeDef err=HAL_SPI_Transmit(oled.device, &cmd, 1, 10);
  269. if(err!=HAL_OK){
  270. Error_Handler();
  271. }
  272. #else
  273. spi_send(&cmd,1);
  274. #endif
  275. #ifdef USE_DC
  276. Oled_Set_DC();
  277. #endif
  278. #ifdef USE_CS
  279. Oled_Set_CS();
  280. #endif
  281. #elif defined OLED_I2C
  282. #if defined OLED_DEVICE && !defined I2C_TRY_HW
  283. if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, &cmd, 1, 100)!=HAL_OK){
  284. Error_Handler();
  285. }
  286. #elif defined OLED_DEVICE && defined I2C_TRY_HW
  287. if(oled.use_sw){
  288. i2cSend(&cmd,1,i2cCmd);
  289. }
  290. else{
  291. if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, &cmd, 1, 100)!=HAL_OK){
  292. Error_Handler();
  293. }
  294. }
  295. #else
  296. i2cSend(&cmd,1,i2cCmd);
  297. #endif
  298. #endif
  299. }
  300. void update_display( void ){
  301. if(oled.status!=oled_idle) { return; } // If OLED busy, skip update
  302. if(oled.row!=0){ Error_Handler(); }
  303. #if (defined OLED_I2C || defined OLED_SPI) && (!defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW))
  304. if(oled.use_sw){
  305. for(uint8_t row=0;row<8;row++){
  306. HAL_IWDG_Refresh(&hiwdg);
  307. setOledRow(row);
  308. #if defined OLED_SPI
  309. #ifdef USE_CS
  310. Oled_Clear_CS();
  311. #endif
  312. #ifdef USE_DC
  313. Oled_Set_DC();
  314. #endif
  315. spi_send((uint8_t *)&oled.buffer[128*row],128);
  316. #ifdef USE_CS
  317. Oled_Set_CS();
  318. #endif
  319. #elif defined OLED_I2C
  320. i2cSend((uint8_t *)&oled.buffer[128*row],128,i2cData);
  321. #endif
  322. }
  323. return;
  324. }
  325. #endif
  326. oled.status=oled_busy;
  327. #if defined OLED_SPI && defined OLED_DEVICE
  328. HAL_SPI_TxCpltCallback(oled.device); // Call the DMA callback function to start sending the frame
  329. #elif defined OLED_I2C && defined OLED_DEVICE
  330. HAL_I2C_MemTxCpltCallback(oled.device); // Call the DMA callback function to start sending the frame
  331. #endif
  332. }
  333. #if !defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW)
  334. void setOledRow(uint8_t row){
  335. write_cmd(0xB0|row); // Set the OLED Row address
  336. write_cmd(systemSettings.settings.OledOffset);
  337. write_cmd(0x10);
  338. }
  339. #endif
  340. void setContrast(uint8_t value) {
  341. write_cmd(0x81); // Set Contrast Control
  342. write_cmd(value); // Default => 0xFF
  343. lastContrast = value;
  344. }
  345. uint8_t getContrast(void) {
  346. return lastContrast;
  347. }
  348. #if defined OLED_SPI && !defined OLED_DEVICE
  349. void ssd1306_init(DMA_HandleTypeDef *dma){
  350. enable_soft_Oled();
  351. #elif defined OLED_SPI && defined OLED_DEVICE
  352. void ssd1306_init(SPI_HandleTypeDef *device,DMA_HandleTypeDef *dma){
  353. oled.device = device;
  354. #elif defined OLED_I2C && defined OLED_DEVICE
  355. void ssd1306_init(I2C_HandleTypeDef *device,DMA_HandleTypeDef *dma){
  356. oled.device = device;
  357. i2c_workaround();
  358. #elif defined OLED_I2C && !defined OLED_DEVICE && !defined I2C_TRY_HW
  359. void ssd1306_init(DMA_HandleTypeDef *dma){
  360. enable_soft_Oled();
  361. #else
  362. #error "Wrong display configuration in board.h!"
  363. #endif
  364. oled.fillDMA= dma;
  365. #if defined OLED_SPI
  366. #ifndef USE_DC
  367. #error Mandatory OLED DC Pin not configured
  368. #endif
  369. #ifdef USE_CS
  370. Oled_Set_CS(); // De-select
  371. #endif
  372. #ifdef USE_RST
  373. Oled_Clear_RES(); // Set RST
  374. HAL_Delay(1); // Delay
  375. Oled_Set_RES(); // Release RST
  376. #endif
  377. #endif
  378. #if defined OLED_I2C
  379. #ifdef USE_CS
  380. Oled_Clear_CS(); // Unused in I2C mode, set low
  381. #endif
  382. #ifdef USE_DC
  383. Oled_Clear_DC(); // DC is the LSB address in I2C mode
  384. #endif
  385. #ifdef USE_RST
  386. Oled_Clear_RES(); // Set RST
  387. HAL_Delay(1);
  388. Oled_Set_RES(); // Release RST
  389. #endif
  390. #endif
  391. systemSettings.settings.OledOffset = 2; // Set by default while system settings are not loaded
  392. HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
  393. HAL_Delay(100); // 100mS wait for internal initialization
  394. #if defined OLED_I2C && defined OLED_DEVICE && defined I2C_TRY_HW
  395. oled.use_sw=1;
  396. //disable_soft_Oled();
  397. //HAL_Delay(1);
  398. // Check if OLED is connected to hardware I2C
  399. for(uint8_t try=0; try<5; try++){
  400. uint8_t data;
  401. uint8_t res = HAL_I2C_Mem_Read(oled.device, OLED_ADDRESS, 0x00, 1, &data, 1, 10);
  402. if(res==HAL_OK){
  403. oled.use_sw=0; // Detected, enable hw
  404. break;
  405. }
  406. HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
  407. HAL_Delay(10); // Failed, wait before next try
  408. }
  409. if(oled.use_sw){ // Display not detected
  410. enable_soft_Oled(); // Set sw mode
  411. }
  412. #elif !defined OLED_DEVICE
  413. oled.use_sw=1;
  414. #endif
  415. write_cmd(0xAE); // Display Off
  416. write_cmd(0xD5); // Set Display Clock Divide Ratio / Oscillator Frequency
  417. write_cmd(0xF0); // Set max framerate
  418. write_cmd(0xA8); // Set Multiplex Ratio
  419. write_cmd(0x3F); // Default => 0x3F (1/64 Duty)
  420. write_cmd(0xD3); // Set Display Offset
  421. write_cmd(0x00); // Default => 0x00
  422. write_cmd(0x40|0x00); // Set Display Start Line
  423. write_cmd(0x20); // Set Memory Addressing Mode
  424. write_cmd(0x02); // Default => 0x02
  425. write_cmd(0xA0|0x01); // Set Segment Re-Map
  426. write_cmd(0xC0|0x08); // Set COM Output Scan Direction
  427. write_cmd(0xDA); // Set COM Pins Hardware Configuration
  428. write_cmd(0x02|0x10); // Default => 0x12 (0x10)
  429. setContrast(0xFF); // Init in max contrast
  430. write_cmd(0xD9); // Set Pre-Charge Period
  431. write_cmd(0x22); // Default => 0x22 (2 Display Clocks [Phase 2] / 2 Display Clocks [Phase 1])
  432. write_cmd(0xDB); // Set VCOMH Deselect Level
  433. write_cmd(0x30); // Default => 0x20 (0.77*VCC)
  434. write_cmd(0xA4|0x00); // Set Entire Display On/Off
  435. write_cmd(0xA6|0x00); // Set Inverse Display On/Off
  436. write_cmd(0x8D); // Set Charge Pump command
  437. write_cmd(0x14); // Enable charge pump
  438. write_cmd(0x33); // Charge pump to 9V
  439. FillBuffer(BLACK,fill_dma); // Clear buffer
  440. update_display(); // Update display CGRAM
  441. while(oled.status!=oled_idle); // Wait for DMA completion (If enabled)
  442. write_cmd(0xAF); // Set Display On
  443. }
  444. /*
  445. * Clear buffer with 32bit-transfer for fast filling (ensure that Oled buffer is 32-bit aligned!)
  446. * 128 * 8 = 1KB, / 4byte DMA txfer = 256 clock cycles (in theory)
  447. * Args:
  448. * color: 0 = black, 1 = white
  449. * mode: 0 = Use software(fail-safe), 1= Use DMA (normal operation)
  450. */
  451. void FillBuffer(bool color, bool mode){
  452. uint32_t fillVal;
  453. while(oled.status!=oled_idle); // Don't write to buffer while screen buffer is being transfered
  454. if(color==WHITE){ fillVal=0xffffffff; } // Fill color = white
  455. else{ fillVal=0; } // Fill color = black
  456. if(mode==fill_dma){ // use DMA
  457. HAL_DMA_Start(oled.fillDMA,(uint32_t)&fillVal,(uint32_t)oled.ptr,sizeof(oled.buffer)/sizeof(uint32_t));
  458. HAL_DMA_PollForTransfer(oled.fillDMA, HAL_DMA_FULL_TRANSFER, 3000);
  459. }
  460. else{ // use software
  461. uint32_t* bf=(uint32_t*)oled.ptr; // Pointer to oled buffer using 32bit data for faster operation
  462. for(uint16_t x=0;x<sizeof(oled.buffer)/sizeof(uint32_t);x++){ // Write to oled buffer
  463. bf[x]=fillVal;
  464. }
  465. }
  466. }
  467. #if (defined OLED_I2C || defined OLED_SPI) && defined OLED_DEVICE
  468. // Abort DMA transfers and reset status
  469. void display_abort(void){
  470. if(oled.device!=NULL){
  471. #if defined OLED_SPI
  472. HAL_SPI_Abort(oled.device);
  473. #elif defined OLED_I2C
  474. HAL_I2C_Master_Abort_IT(oled.device, 0);
  475. #endif
  476. __HAL_UNLOCK(oled.device);
  477. HAL_DMA_PollForTransfer(oled.device->hdmatx, HAL_DMA_FULL_TRANSFER, 100); // Wait for DMA to finish
  478. }
  479. oled.status=oled_idle; // Force oled idle status
  480. }
  481. // Screen update for hard error handlers (crashes) not using DMA
  482. void update_display_ErrorHandler(void){
  483. for(uint8_t row=0;row<8;row++){
  484. uint8_t cmd[3]={
  485. 0xB0|row,
  486. systemSettings.settings.OledOffset,
  487. 0x10
  488. };
  489. #ifdef OLED_SPI
  490. #ifdef USE_CS
  491. Oled_Clear_CS();
  492. #endif
  493. #ifdef USE_DC
  494. Oled_Clear_DC();
  495. #endif
  496. if(HAL_SPI_Transmit(oled.device, cmd, 3, 50)){
  497. while(1){ // If error happens at this stage, just do nothing
  498. HAL_IWDG_Refresh(&hiwdg);
  499. }
  500. }
  501. #ifdef USE_DC
  502. Oled_Set_DC();
  503. #endif
  504. if(HAL_SPI_Transmit(oled.device, (uint8_t*)oled.ptr + (row * 128), 128, 1000)!=HAL_OK){
  505. while(1){ // If error happens at this stage, just do nothing
  506. HAL_IWDG_Refresh(&hiwdg);
  507. }
  508. }
  509. #elif defined OLED_I2C
  510. if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, cmd, 3, 50)){
  511. while(1){ // If error happens at this stage, just do nothing
  512. HAL_IWDG_Refresh(&hiwdg);
  513. }
  514. }
  515. if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x40, 1, (uint8_t*)oled.ptr + (row * 128), 128, 1000)!=HAL_OK){
  516. while(1){ // If error happens at this stage, just do nothing
  517. HAL_IWDG_Refresh(&hiwdg);
  518. }
  519. }
  520. #endif
  521. }
  522. #if defined OLED_SPI && defined USE_CS
  523. Oled_Set_CS();
  524. #endif
  525. }
  526. #ifdef OLED_SPI
  527. void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *device){
  528. #elif defined OLED_I2C
  529. void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *device){
  530. #endif
  531. if(device == oled.device){
  532. HAL_DMA_PollForTransfer(oled.device->hdmatx, HAL_DMA_FULL_TRANSFER, 10); //Wait for DMA to finish
  533. if(oled.row>7){
  534. #if defined OLED_SPI && defined USE_CS
  535. Oled_Set_CS(); // Release CS
  536. #endif
  537. oled.row=0; // Reset row position
  538. oled.status=oled_idle;
  539. return; // Return without retriggering DMA.
  540. }
  541. uint8_t cmd[3]={
  542. 0xB0|oled.row,
  543. systemSettings.settings.OledOffset,
  544. 0x10
  545. };
  546. #ifdef OLED_SPI
  547. #ifdef USE_CS
  548. Oled_Clear_CS();
  549. #endif
  550. #ifdef USE_DC
  551. Oled_Clear_DC();
  552. #endif
  553. uint8_t try =3;
  554. while(try){
  555. if(HAL_SPI_Transmit(oled.device, cmd, 3, 50)==HAL_OK){ // Send row command in blocking mode
  556. break;
  557. }
  558. else{
  559. display_abort();
  560. oled.status=oled_busy;
  561. try--;
  562. }
  563. }
  564. if(try==0){
  565. Error_Handler();
  566. }
  567. #ifdef USE_DC
  568. Oled_Set_DC();
  569. #endif
  570. if(HAL_SPI_Transmit_DMA(oled.device,(uint8_t *) oled.ptr+((uint16_t)128*oled.row), 128)!= HAL_OK){ // Send row data in DMA interrupt mode
  571. Error_Handler();
  572. }
  573. #elif defined OLED_I2C
  574. uint8_t try =3;
  575. while(try){
  576. if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, cmd, 3, 50)==HAL_OK){
  577. break;
  578. }
  579. else{
  580. display_abort();
  581. oled.status=oled_busy;
  582. try--;
  583. }
  584. }
  585. if(HAL_I2C_Mem_Write_DMA(oled.device, OLED_ADDRESS, 0x40, 1, oled.ptr+(128*oled.row), 128)!=HAL_OK){
  586. Error_Handler();
  587. }
  588. #endif
  589. oled.row++;
  590. }
  591. }
  592. #endif
  593. void FatalError(uint8_t type){
  594. #if (defined OLED_I2C || defined OLED_SPI) && defined OLED_DEVICE
  595. if(!oled.use_sw){
  596. display_abort();
  597. }
  598. #endif
  599. SetFailState(setError);
  600. buzzer_fatal_beep();
  601. Diag_init();
  602. switch(type){
  603. case error_NMI:
  604. putStrAligned("NMI HANDLER", 0, align_center);
  605. break;
  606. case error_HARDFAULT:
  607. putStrAligned("HARD FAULT", 0, align_center);
  608. break;
  609. case error_MEMMANAGE:
  610. putStrAligned("MEM MANAGE", 0, align_center);
  611. break;
  612. case error_BUSFAULT:
  613. putStrAligned("BUS FAULT", 0, align_center);
  614. break;
  615. case error_USAGEFAULT:
  616. putStrAligned("USAGE FAULT", 0, align_center);
  617. break;
  618. case error_RUNAWAY25:
  619. case error_RUNAWAY50:
  620. case error_RUNAWAY75:
  621. case error_RUNAWAY100:
  622. {
  623. uint8_t level = 25 * ((type - error_RUNAWAY25)+1);
  624. char strRunawayLevel[8];
  625. sprintf(strRunawayLevel,">%u\260C\n",level);
  626. putStrAligned("TEMP RUNAWAY", 0, align_center);
  627. putStrAligned(strRunawayLevel, 15, align_center);
  628. break;
  629. }
  630. case error_RUNAWAY500:
  631. putStrAligned("EXCEEDED", 0, align_center);
  632. putStrAligned("500\260C!", 15, align_center);
  633. break;
  634. case error_RUNAWAY_UNKNOWN:
  635. putStrAligned("TEMP RUNAWAY", 0, align_center);
  636. putStrAligned("UNDEFINED!", 15, align_center);
  637. break;
  638. default:
  639. putStrAligned("UNKNOWN ERROR", 0, align_center);
  640. break;
  641. }
  642. putStrAligned("SYSTEM HALTED", 35, align_center);
  643. putStrAligned("Use btn to reset", 50, align_center);
  644. #if (defined OLED_I2C || defined OLED_SPI) && defined OLED_DEVICE
  645. if(!oled.use_sw){
  646. update_display_ErrorHandler();
  647. }
  648. #if defined OLED_I2C && defined I2C_TRY_HW
  649. else{
  650. update_display();
  651. }
  652. #endif
  653. #else
  654. update_display();
  655. #endif
  656. Reset_onError();
  657. }
  658. void putStrAligned(char* str, uint8_t y, AlignType align){
  659. if(align==align_left){
  660. u8g2_DrawStr(&u8g2, 0, y, str);
  661. }
  662. else{
  663. uint8_t len = u8g2_GetStrWidth(&u8g2, str);
  664. if(align==align_center){
  665. u8g2_DrawStr(&u8g2, ((OledWidth-1)-len)/2, y, str);
  666. }
  667. else if(align==align_right){
  668. u8g2_DrawStr(&u8g2, (OledWidth-1)-len, y, str);
  669. }
  670. }
  671. }
  672. void Reset_onError(void){
  673. __disable_irq();
  674. while(BUTTON_input()){ // Wait until the button is pressed
  675. for(uint16_t i=0;i<50000;i++); // Small delay
  676. HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
  677. }
  678. while(!BUTTON_input()){ // Wait until the button is released
  679. for(uint16_t i=0;i<50000;i++); // Small delay
  680. HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
  681. }
  682. NVIC_SystemReset(); // Reset system
  683. }