123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808 |
- #include "ssd1306.h"
- #include "settings.h"
- #include "buzzer.h"
- #include "iron.h"
- #include "gui.h"
- oled_t oled = {
- .ptr = &oled.buffer[0]
- };
- static uint8_t lastContrast;
- // Silicon bug workaround for STM32F103 as ST document ES093 rev 7
- /*
- __HAL_I2C_DISABLE(device);
- HW_SCL_GPIO_Port->ODR |= HW_SCL_Pin;
- HW_SDA_GPIO_Port->ODR |= HW_SDA_Pin;
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- GPIO_InitStruct.Pin = SW_SCL_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = SW_SDA_Pin;
- HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
- // SCL, SDA HIGH
- while( !(HW_SDA_GPIO_Port->IDR & HW_SDA_Pin) || !(HW_SCL_GPIO_Port->IDR & HW_SCL_Pin) );
- // SDA LOW
- HW_SDA_GPIO_Port->ODR &= ~(HW_SDA_Pin);
- while(HW_SDA_GPIO_Port->IDR & HW_SDA_Pin);
- // SCL LOW
- HW_SCL_GPIO_Port->ODR &= ~(HW_SCL_Pin);
- while(HW_SCL_GPIO_Port->IDR & HW_SCL_Pin);
- // SCL HIGH
- HW_SCL_GPIO_Port->ODR |= HW_SCL_Pin;
- while(!(HW_SCL_GPIO_Port->IDR & HW_SCL_Pin));
- // SDA HIGH
- HW_SDA_GPIO_Port->ODR |= HW_SDA_Pin;
- while(!(HW_SDA_GPIO_Port->IDR & HW_SDA_Pin));
- GPIO_InitStruct.Pin = SW_SCL_Pin;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
- HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = SW_SDA_Pin;
- HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
- device->Instance->CR1 |= I2C_CR1_SWRST;
- device->Instance->CR1 &= ~(I2C_CR1_SWRST);
- __HAL_I2C_ENABLE(device);
- */
- #if defined OLED_I2C && defined OLED_DEVICE
- // Silicon bug workaround for STM32F103, force I2C RCC reset and re-init
- void i2c_workaround(void){
- __HAL_RCC_I2C1_FORCE_RESET();
- __HAL_RCC_I2C2_FORCE_RESET();
- HAL_Delay(10);
- __HAL_RCC_I2C1_RELEASE_RESET();
- __HAL_RCC_I2C2_RELEASE_RESET();
- oled.device->State = HAL_I2C_STATE_RESET;
- __HAL_RCC_DMA1_CLK_ENABLE();
- oled.device->Instance = I2C1;
- oled.device->Init.ClockSpeed = 400000;
- oled.device->Init.DutyCycle = I2C_DUTYCYCLE_2;
- oled.device->Init.OwnAddress1 = 0;
- oled.device->Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
- oled.device->Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
- oled.device->Init.OwnAddress2 = 0;
- oled.device->Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
- oled.device->Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
- if (HAL_I2C_Init(oled.device) != HAL_OK){
- Error_Handler();
- }
- }
- #endif
- #if (defined OLED_SPI && !defined OLED_DEVICE) || (defined OLED_I2C && (!defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW)))
- void enable_soft_Oled(void){
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- #if defined HW_SCL_Pin && defined HW_SDA_Pin
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- /*Configure GPIO pins : SDA_Pin */
- GPIO_InitStruct.Pin = HW_SDA_Pin;
- HAL_GPIO_Init(HW_SDA_GPIO_Port, &GPIO_InitStruct);
- /*Configure GPIO pins : SDA_Pin */
- GPIO_InitStruct.Pin = HW_SCL_Pin;
- HAL_GPIO_Init(HW_SCL_GPIO_Port, &GPIO_InitStruct);
- #endif
- #if defined SW_SDA_Pin && defined SW_SCL_Pin
- Oled_Set_SDA();
- Oled_Set_SCL();
- #ifdef OLED_I2C
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
- #else
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- #endif
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- /*Configure GPIO pins : SCL_Pin */
- GPIO_InitStruct.Pin = SW_SCL_Pin;
- HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
- /*Configure GPIO pins : SDA_Pin */
- GPIO_InitStruct.Pin = SW_SDA_Pin;
- HAL_GPIO_Init(SW_SDA_GPIO_Port, &GPIO_InitStruct);
- #endif
- #ifdef OLED_I2C
- // Reset the bus
- i2cStart();
- Oled_Set_SDA();
- for(uint8_t c=0;c<9;c++){
- Oled_Set_SCL();
- i2cDelay();
- Oled_Clear_SCL();
- i2cDelay();
- }
- i2cStop();
- #endif
- }
- void disable_soft_Oled(void){
- GPIO_InitTypeDef GPIO_InitStruct = {0};
- #if defined SW_SCL_Pin && defined SW_SDA_Pin
- GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
- GPIO_InitStruct.Pull = GPIO_NOPULL;
- GPIO_InitStruct.Pin = SW_SCL_Pin;
- HAL_GPIO_Init(SW_SCL_GPIO_Port, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = SW_SDA_Pin;
- HAL_GPIO_Init(SW_SDA_GPIO_Port, &GPIO_InitStruct);
- #endif
- #if defined HW_SCL_Pin && defined HW_SDA_PIN
- GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- GPIO_InitStruct.Pin = HW_SDA_Pin;
- HAL_GPIO_Init(HW_SDA_GPIO_Port, &GPIO_InitStruct);
- GPIO_InitStruct.Pin = HW_SCL_Pin;
- HAL_GPIO_Init(HW_SCL_GPIO_Port, &GPIO_InitStruct);
- #endif
- }
- #endif
- #if defined OLED_SPI && !defined OLED_DEVICE
- void spi_send(uint8_t* bf, uint16_t count){
- uint8_t shift,data;
- while(count--){
- data = *bf++;
- if((data==0) || (data==0xFF)){
- if(data==0)
- Oled_Clear_SDA();
- else
- Oled_Set_SDA();
- // Much faster without a loop!
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- Oled_Set_SCL();
- Oled_Clear_SCL();
- }
- else{
- for(shift = 0; shift < 8; shift++){
- if(data & 0x80){
- Oled_Set_SDA();
- }
- else{
- Oled_Clear_SDA();
- }
- Oled_Set_SCL();
- data <<= 1;
- Oled_Clear_SCL();
- }
- }
- }
- }
- #endif
- #if defined OLED_I2C && (!defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW))
- void i2cDelay(void){
- asm( "nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop\n\
- nop\nnop\nnop\nnop\nnop\nnop\nnop/*\nnop\n\
- nop\nnop\nnop\nnop\nnop\nnop\nnop\nnop*/");
- }
- void i2cStart(void){ // Start condition, SDA transition to low with SCL high
- Oled_Set_SCL();
- i2cDelay();
- Oled_Clear_SDA();
- i2cDelay();
- Oled_Clear_SCL();
- i2cDelay();
- }
- void i2cStop(void){ // Stop condition, SCL transition to high with SDA low
- Oled_Clear_SDA();
- i2cDelay();
- Oled_Set_SCL();
- i2cDelay();
- Oled_Set_SDA();
- i2cDelay();
- }
- // This sw i2c driver is extremely timing optimized, done specially for ksger v2.1 and compatibles running at 36MHz.
- // Hacks clock low time using the slow rise time (i2c pullup resistors) as the delay.
- // Will start failing if the core runs faster than 44-48MHz because of the tight timing.
- void i2cBegin(uint8_t mode){
- uint8_t bytes, shift, data[2]= { OLED_ADDRESS, mode };
- uint8_t *bf=data;
- bytes=1;
- do{
- shift=7;
- do{
- SW_SDA_GPIO_Port->BSRR = SW_SDA_Pin<<(16*!(*bf & (1<<shift)));
- Oled_Set_SCL();
- i2cDelay();
- Oled_Clear_SCL();
- }while(shift--);
- i2cDelay();
- Oled_Set_SCL();
- i2cDelay();
- //Oled_Set_SDA(); // As we don't care about the ACK, don't release SDA
- //i2cDelay();
- //Get ACK here
- Oled_Clear_SCL();
- bf++;
- }while(bytes--);
- }
- void i2cSend(uint8_t* bf, uint16_t count, uint8_t mode){
- uint8_t shift;
- i2cStart();
- i2cBegin(mode);
- while(count--){
- shift=7;
- if( (*bf==0)||(*bf==0xFF)){ // If data 0 or 0xff, we don't have to toggle data line, send the data fast
- SW_SDA_GPIO_Port->BSRR = SW_SDA_Pin<<(16*(*bf==0));
- do{
- Oled_Set_SCL();
- i2cDelay();
- Oled_Clear_SCL();
- }while(shift--);
- }
- else{
- do{
- SW_SDA_GPIO_Port->BSRR = SW_SDA_Pin<<(16*!(*bf & (1<<shift)));
- Oled_Set_SCL();
- i2cDelay();
- Oled_Clear_SCL();
- }while(shift--);
- }
- i2cDelay();
- Oled_Set_SCL();
- i2cDelay();
- //Oled_Set_SDA(); // As we don't care about the ACK, don't release SDA
- //i2cDelay();
- //Get ACK here
- Oled_Clear_SCL();
- bf++;
- }
- i2cStop();
- }
- #endif
- // Send command in blocking mode
- void write_cmd(uint8_t cmd) {
- while(oled.status==oled_busy); // Wait for DMA to finish
- #if defined OLED_SPI
- #ifdef USE_CS
- Oled_Clear_CS();
- #endif
- #ifdef USE_DC
- Oled_Clear_DC();
- #endif
- #ifdef OLED_DEVICE
- HAL_StatusTypeDef err=HAL_SPI_Transmit(oled.device, &cmd, 1, 10);
- if(err!=HAL_OK){
- Error_Handler();
- }
- #else
- spi_send(&cmd,1);
- #endif
- #ifdef USE_DC
- Oled_Set_DC();
- #endif
- #ifdef USE_CS
- Oled_Set_CS();
- #endif
- #elif defined OLED_I2C
- #if defined OLED_DEVICE && !defined I2C_TRY_HW
- if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, &cmd, 1, 100)!=HAL_OK){
- Error_Handler();
- }
- #elif defined OLED_DEVICE && defined I2C_TRY_HW
- if(oled.use_sw){
- i2cSend(&cmd,1,i2cCmd);
- }
- else{
- if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, &cmd, 1, 100)!=HAL_OK){
- Error_Handler();
- }
- }
- #else
- i2cSend(&cmd,1,i2cCmd);
- #endif
- #endif
- }
- void update_display( void ){
- if(oled.status!=oled_idle) { return; } // If OLED busy, skip update
- if(oled.row!=0){ Error_Handler(); }
- #if (defined OLED_I2C || defined OLED_SPI) && (!defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW))
- if(oled.use_sw){
- for(uint8_t row=0;row<8;row++){
- HAL_IWDG_Refresh(&hiwdg);
- setOledRow(row);
- #if defined OLED_SPI
- #ifdef USE_CS
- Oled_Clear_CS();
- #endif
- #ifdef USE_DC
- Oled_Set_DC();
- #endif
- spi_send((uint8_t *)&oled.buffer[128*row],128);
- #ifdef USE_CS
- Oled_Set_CS();
- #endif
- #elif defined OLED_I2C
- i2cSend((uint8_t *)&oled.buffer[128*row],128,i2cData);
- #endif
- }
- return;
- }
- #endif
- oled.status=oled_busy;
- #if defined OLED_SPI && defined OLED_DEVICE
- HAL_SPI_TxCpltCallback(oled.device); // Call the DMA callback function to start sending the frame
- #elif defined OLED_I2C && defined OLED_DEVICE
- HAL_I2C_MemTxCpltCallback(oled.device); // Call the DMA callback function to start sending the frame
- #endif
- }
- #if !defined OLED_DEVICE || (defined OLED_DEVICE && defined I2C_TRY_HW)
- void setOledRow(uint8_t row){
- write_cmd(0xB0|row); // Set the OLED Row address
- write_cmd(systemSettings.settings.OledOffset);
- write_cmd(0x10);
- }
- #endif
- void setContrast(uint8_t value) {
- write_cmd(0x81); // Set Contrast Control
- write_cmd(value); // Default => 0xFF
- lastContrast = value;
- }
- uint8_t getContrast(void) {
- return lastContrast;
- }
- #if defined OLED_SPI && !defined OLED_DEVICE
- void ssd1306_init(DMA_HandleTypeDef *dma){
- enable_soft_Oled();
- #elif defined OLED_SPI && defined OLED_DEVICE
- void ssd1306_init(SPI_HandleTypeDef *device,DMA_HandleTypeDef *dma){
- oled.device = device;
- #elif defined OLED_I2C && defined OLED_DEVICE
- void ssd1306_init(I2C_HandleTypeDef *device,DMA_HandleTypeDef *dma){
- oled.device = device;
- i2c_workaround();
- #elif defined OLED_I2C && !defined OLED_DEVICE && !defined I2C_TRY_HW
- void ssd1306_init(DMA_HandleTypeDef *dma){
- enable_soft_Oled();
- #else
- #error "Wrong display configuration in board.h!"
- #endif
- oled.fillDMA= dma;
- #if defined OLED_SPI
- #ifndef USE_DC
- #error Mandatory OLED DC Pin not configured
- #endif
- #ifdef USE_CS
- Oled_Set_CS(); // De-select
- #endif
- #ifdef USE_RST
- Oled_Clear_RES(); // Set RST
- HAL_Delay(1); // Delay
- Oled_Set_RES(); // Release RST
- #endif
- #endif
- #if defined OLED_I2C
- #ifdef USE_CS
- Oled_Clear_CS(); // Unused in I2C mode, set low
- #endif
- #ifdef USE_DC
- Oled_Clear_DC(); // DC is the LSB address in I2C mode
- #endif
- #ifdef USE_RST
- Oled_Clear_RES(); // Set RST
- HAL_Delay(1);
- Oled_Set_RES(); // Release RST
- #endif
- #endif
- systemSettings.settings.OledOffset = 2; // Set by default while system settings are not loaded
- HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
- HAL_Delay(100); // 100mS wait for internal initialization
- #if defined OLED_I2C && defined OLED_DEVICE && defined I2C_TRY_HW
- oled.use_sw=1;
- //disable_soft_Oled();
- //HAL_Delay(1);
- // Check if OLED is connected to hardware I2C
- for(uint8_t try=0; try<5; try++){
- uint8_t data;
- uint8_t res = HAL_I2C_Mem_Read(oled.device, OLED_ADDRESS, 0x00, 1, &data, 1, 10);
- if(res==HAL_OK){
- oled.use_sw=0; // Detected, enable hw
- break;
- }
- HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
- HAL_Delay(10); // Failed, wait before next try
- }
- if(oled.use_sw){ // Display not detected
- enable_soft_Oled(); // Set sw mode
- }
- #elif !defined OLED_DEVICE
- oled.use_sw=1;
- #endif
- write_cmd(0xAE); // Display Off
- write_cmd(0xD5); // Set Display Clock Divide Ratio / Oscillator Frequency
- write_cmd(0xF0); // Set max framerate
- write_cmd(0xA8); // Set Multiplex Ratio
- write_cmd(0x3F); // Default => 0x3F (1/64 Duty)
- write_cmd(0xD3); // Set Display Offset
- write_cmd(0x00); // Default => 0x00
- write_cmd(0x40|0x00); // Set Display Start Line
- write_cmd(0x20); // Set Memory Addressing Mode
- write_cmd(0x02); // Default => 0x02
- write_cmd(0xA0|0x01); // Set Segment Re-Map
- write_cmd(0xC0|0x08); // Set COM Output Scan Direction
- write_cmd(0xDA); // Set COM Pins Hardware Configuration
- write_cmd(0x02|0x10); // Default => 0x12 (0x10)
- setContrast(0xFF); // Init in max contrast
- write_cmd(0xD9); // Set Pre-Charge Period
- write_cmd(0x22); // Default => 0x22 (2 Display Clocks [Phase 2] / 2 Display Clocks [Phase 1])
- write_cmd(0xDB); // Set VCOMH Deselect Level
- write_cmd(0x30); // Default => 0x20 (0.77*VCC)
- write_cmd(0xA4|0x00); // Set Entire Display On/Off
- write_cmd(0xA6|0x00); // Set Inverse Display On/Off
- write_cmd(0x8D); // Set Charge Pump command
- write_cmd(0x14); // Enable charge pump
- write_cmd(0x33); // Charge pump to 9V
- FillBuffer(BLACK,fill_dma); // Clear buffer
- update_display(); // Update display CGRAM
- while(oled.status!=oled_idle); // Wait for DMA completion (If enabled)
- write_cmd(0xAF); // Set Display On
- }
- /*
- * Clear buffer with 32bit-transfer for fast filling (ensure that Oled buffer is 32-bit aligned!)
- * 128 * 8 = 1KB, / 4byte DMA txfer = 256 clock cycles (in theory)
- * Args:
- * color: 0 = black, 1 = white
- * mode: 0 = Use software(fail-safe), 1= Use DMA (normal operation)
- */
- void FillBuffer(bool color, bool mode){
- uint32_t fillVal;
- while(oled.status!=oled_idle); // Don't write to buffer while screen buffer is being transfered
- if(color==WHITE){ fillVal=0xffffffff; } // Fill color = white
- else{ fillVal=0; } // Fill color = black
- if(mode==fill_dma){ // use DMA
- HAL_DMA_Start(oled.fillDMA,(uint32_t)&fillVal,(uint32_t)oled.ptr,sizeof(oled.buffer)/sizeof(uint32_t));
- HAL_DMA_PollForTransfer(oled.fillDMA, HAL_DMA_FULL_TRANSFER, 3000);
- }
- else{ // use software
- uint32_t* bf=(uint32_t*)oled.ptr; // Pointer to oled buffer using 32bit data for faster operation
- for(uint16_t x=0;x<sizeof(oled.buffer)/sizeof(uint32_t);x++){ // Write to oled buffer
- bf[x]=fillVal;
- }
- }
- }
- #if (defined OLED_I2C || defined OLED_SPI) && defined OLED_DEVICE
- // Abort DMA transfers and reset status
- void display_abort(void){
- if(oled.device!=NULL){
- #if defined OLED_SPI
- HAL_SPI_Abort(oled.device);
- #elif defined OLED_I2C
- HAL_I2C_Master_Abort_IT(oled.device, 0);
- #endif
- __HAL_UNLOCK(oled.device);
- HAL_DMA_PollForTransfer(oled.device->hdmatx, HAL_DMA_FULL_TRANSFER, 100); // Wait for DMA to finish
- }
- oled.status=oled_idle; // Force oled idle status
- }
- // Screen update for hard error handlers (crashes) not using DMA
- void update_display_ErrorHandler(void){
- for(uint8_t row=0;row<8;row++){
- uint8_t cmd[3]={
- 0xB0|row,
- systemSettings.settings.OledOffset,
- 0x10
- };
- #ifdef OLED_SPI
- #ifdef USE_CS
- Oled_Clear_CS();
- #endif
- #ifdef USE_DC
- Oled_Clear_DC();
- #endif
- if(HAL_SPI_Transmit(oled.device, cmd, 3, 50)){
- while(1){ // If error happens at this stage, just do nothing
- HAL_IWDG_Refresh(&hiwdg);
- }
- }
- #ifdef USE_DC
- Oled_Set_DC();
- #endif
- if(HAL_SPI_Transmit(oled.device, (uint8_t*)oled.ptr + (row * 128), 128, 1000)!=HAL_OK){
- while(1){ // If error happens at this stage, just do nothing
- HAL_IWDG_Refresh(&hiwdg);
- }
- }
- #elif defined OLED_I2C
- if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, cmd, 3, 50)){
- while(1){ // If error happens at this stage, just do nothing
- HAL_IWDG_Refresh(&hiwdg);
- }
- }
- if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x40, 1, (uint8_t*)oled.ptr + (row * 128), 128, 1000)!=HAL_OK){
- while(1){ // If error happens at this stage, just do nothing
- HAL_IWDG_Refresh(&hiwdg);
- }
- }
- #endif
- }
- #if defined OLED_SPI && defined USE_CS
- Oled_Set_CS();
- #endif
- }
- #ifdef OLED_SPI
- void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *device){
- #elif defined OLED_I2C
- void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *device){
- #endif
- if(device == oled.device){
- HAL_DMA_PollForTransfer(oled.device->hdmatx, HAL_DMA_FULL_TRANSFER, 10); //Wait for DMA to finish
- if(oled.row>7){
- #if defined OLED_SPI && defined USE_CS
- Oled_Set_CS(); // Release CS
- #endif
- oled.row=0; // Reset row position
- oled.status=oled_idle;
- return; // Return without retriggering DMA.
- }
- uint8_t cmd[3]={
- 0xB0|oled.row,
- systemSettings.settings.OledOffset,
- 0x10
- };
- #ifdef OLED_SPI
- #ifdef USE_CS
- Oled_Clear_CS();
- #endif
- #ifdef USE_DC
- Oled_Clear_DC();
- #endif
- uint8_t try =3;
- while(try){
- if(HAL_SPI_Transmit(oled.device, cmd, 3, 50)==HAL_OK){ // Send row command in blocking mode
- break;
- }
- else{
- display_abort();
- oled.status=oled_busy;
- try--;
- }
- }
- if(try==0){
- Error_Handler();
- }
- #ifdef USE_DC
- Oled_Set_DC();
- #endif
- 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
- Error_Handler();
- }
- #elif defined OLED_I2C
- uint8_t try =3;
- while(try){
- if(HAL_I2C_Mem_Write(oled.device, OLED_ADDRESS, 0x00, 1, cmd, 3, 50)==HAL_OK){
- break;
- }
- else{
- display_abort();
- oled.status=oled_busy;
- try--;
- }
- }
- if(HAL_I2C_Mem_Write_DMA(oled.device, OLED_ADDRESS, 0x40, 1, oled.ptr+(128*oled.row), 128)!=HAL_OK){
- Error_Handler();
- }
- #endif
- oled.row++;
- }
- }
- #endif
- void FatalError(uint8_t type){
- #if (defined OLED_I2C || defined OLED_SPI) && defined OLED_DEVICE
- if(!oled.use_sw){
- display_abort();
- }
- #endif
- SetFailState(setError);
- buzzer_fatal_beep();
- Diag_init();
- switch(type){
- case error_NMI:
- putStrAligned("NMI HANDLER", 0, align_center);
- break;
- case error_HARDFAULT:
- putStrAligned("HARD FAULT", 0, align_center);
- break;
- case error_MEMMANAGE:
- putStrAligned("MEM MANAGE", 0, align_center);
- break;
- case error_BUSFAULT:
- putStrAligned("BUS FAULT", 0, align_center);
- break;
- case error_USAGEFAULT:
- putStrAligned("USAGE FAULT", 0, align_center);
- break;
- case error_RUNAWAY25:
- case error_RUNAWAY50:
- case error_RUNAWAY75:
- case error_RUNAWAY100:
- {
- uint8_t level = 25 * ((type - error_RUNAWAY25)+1);
- char strRunawayLevel[8];
- sprintf(strRunawayLevel,">%u\260C\n",level);
- putStrAligned("TEMP RUNAWAY", 0, align_center);
- putStrAligned(strRunawayLevel, 15, align_center);
- break;
- }
- case error_RUNAWAY500:
- putStrAligned("EXCEEDED", 0, align_center);
- putStrAligned("500\260C!", 15, align_center);
- break;
- case error_RUNAWAY_UNKNOWN:
- putStrAligned("TEMP RUNAWAY", 0, align_center);
- putStrAligned("UNDEFINED!", 15, align_center);
- break;
- default:
- putStrAligned("UNKNOWN ERROR", 0, align_center);
- break;
- }
- putStrAligned("SYSTEM HALTED", 35, align_center);
- putStrAligned("Use btn to reset", 50, align_center);
- #if (defined OLED_I2C || defined OLED_SPI) && defined OLED_DEVICE
- if(!oled.use_sw){
- update_display_ErrorHandler();
- }
- #if defined OLED_I2C && defined I2C_TRY_HW
- else{
- update_display();
- }
- #endif
- #else
- update_display();
- #endif
- Reset_onError();
- }
- void putStrAligned(char* str, uint8_t y, AlignType align){
- if(align==align_left){
- u8g2_DrawStr(&u8g2, 0, y, str);
- }
- else{
- uint8_t len = u8g2_GetStrWidth(&u8g2, str);
- if(align==align_center){
- u8g2_DrawStr(&u8g2, ((OledWidth-1)-len)/2, y, str);
- }
- else if(align==align_right){
- u8g2_DrawStr(&u8g2, (OledWidth-1)-len, y, str);
- }
- }
- }
- void Reset_onError(void){
- __disable_irq();
- while(BUTTON_input()){ // Wait until the button is pressed
- for(uint16_t i=0;i<50000;i++); // Small delay
- HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
- }
- while(!BUTTON_input()){ // Wait until the button is released
- for(uint16_t i=0;i<50000;i++); // Small delay
- HAL_IWDG_Refresh(&hiwdg); // Clear watchdog
- }
- NVIC_SystemReset(); // Reset system
- }
|