Git Product home page Git Product logo

Comments (14)

RoCorbera avatar RoCorbera commented on May 29, 2024

Yes, BlueVGA depends on Timers to create the VGA signals correctly.
Systick ISR runs an interrupt every 1 ms and it causes the screen to glitch.

BlueVGA uses Timer1 for the scanline with an interrupt at 31.46875 kHz and Timer4 to count 525 scanlines, which in turn makes 1 frame that takes 16.6666 ms (1/60 second). One scanline takes 31.77756 microseconds.

Therefore, we may think in this way:

  • 1 Frame (16,6666ms) + 42 scanlines... This is 42 * 31.77756 + 16,666.66 microseconds = 18,001 microseconds = 18ms

You may want to expose scanLineCounter used in sendScanLine(void), in the same way frameNumber works.
This way, 18ms will be about 566 scan lines, in time measuring...

The necessary changes to the Source Code would be:
Turn scanLineCounter a volatile external variable, like frameNumber.
Remove Line 183 from https://github.com/RoCorbera/BlueVGA/blob/Graph-Pixels/src/bluevgadriver.c#L177
Add Line 59 like this volatile uint32_t scanLineCounter = 0; right after Line 58
https://github.com/RoCorbera/BlueVGA/blob/Graph-Pixels/src/bluevgadriver.c#L58
Remove Line https://github.com/RoCorbera/BlueVGA/blob/Graph-Pixels/src/bluevgadriver.c#L194 to keep it counting.

Everything must be done in sync, in order that the first thing your software does is to set the line low and start counting the number of scanlines.
For that, you may just send the DHT-11 Start signal right after a vga.waitVSync(1).
This is important because the sketch never runs when the VGA driver is drawing the screen, therefore, the process of scanline counting can't just end at any time. The sketch runs in the VGA Vertical blanking interval

  pinMode(DHT11, OUTPUT);
  vga.waitVSync(1);  // sync the start of the pulse with the VGA VBLANK beginging.
  //scanLineCunter would be exposed as described above. 
  // The sketch needs to declare: extern volatile uint32_t scanLineCounter;
  uint32_t scanLine_18ms = scanLineCounter + 566;  // 566 x 31.77756 us = 18ms
  digitalWrite(DHT11, LOW); 
  while (scanLineCounter < scanLine_18ms); // wait 18ms
  // this may take a couple microseconds, therefore, it may need to reduce 566 to 560 instead...
  // better check all timing with some logic data analyser
  digitalWrtie(DHT11, HIGH);  

  // now start TIMER2 capture, etc.
  Response();
  // at the end of the DHT11 response, disable TIMER2 to stop the screen glitch.

A second problem would be the function Response() that uses Timer2 ISR...
It also depends on interrupts and it will also glitch the screen.
But it would be done very fast and for a short time.
Maybe not a big problem for your application.

from bluevga.

RoCorbera avatar RoCorbera commented on May 29, 2024

I have changed the code to add getScanLineNumber().
Using the source code from github main branch, it would be like that:

  pinMode(DHT11, OUTPUT);
  vga.waitVSync(1);  // sync the start of the pulse with the VGA VBLANK beginging.
  //scanLineCunter would be exposed as described above. 
  // The sketch needs to declare: extern volatile uint32_t scanLineCounter;
  uint32_t scanLine_18ms = vga.getScanLineNumber() + 566;  // 566 x 31.77756 us = 18ms
  digitalWrite(DHT11, LOW); 
  while (vga.getScanLineNumber() < scanLine_18ms); // wait 18ms
  // this may take a couple microseconds, therefore, it may need to reduce 566 to 560 instead...
  // better check all timing with some logic data analyser
  digitalWrtie(DHT11, HIGH);  

  // now start TIMER2 capture, etc.
  Response();
  // at the end of the DHT11 response, disable TIMER2 to stop the screen glitch.

You may get the changes by cloning master branch. downloading the zip file or by pulling from it, using git pull
The Zip File with the master branch latest code can be obtained from https://github.com/RoCorbera/BlueVGA/archive/refs/heads/master.zip

from bluevga.

RoCorbera avatar RoCorbera commented on May 29, 2024

@kingodragon - Actually it may not work... VBLANK is just 35 scanlines per frame. Therefore waiting for 566 scanlines means 525 + 41 scanlines, which will make the end of the 18ms to out of the 2nd VBLANK interval...

The MCU also runs just a few cycles of the sketch per scanline in the HBLANK remaining time.
Maybe if you use GPIO->ODR instead of digitalWrite() to change the state of pin DHT11, it may need just a few cycles and work....

As you can see, BlueVGA uses 90% of the CPU just to drive the VGA signals... there is very few CPU for the other needs.
Another alternative would be try to generate the 18ms pulse also using TIM2 instead of doing it using software bitbang.

I hope you figure out a way to make it work.
Please post here your final solution for other users.

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

I have changed the code to add getScanLineNumber(). Using the source code from github main branch, it would be like that:

  pinMode(DHT11, OUTPUT);
  vga.waitVSync(1);  // sync the start of the pulse with the VGA VBLANK beginging.
  //scanLineCunter would be exposed as described above. 
  // The sketch needs to declare: extern volatile uint32_t scanLineCounter;
  uint32_t scanLine_18ms = vga.getScanLineNumber() + 566;  // 566 x 31.77756 us = 18ms
  digitalWrite(DHT11, LOW); 
  while (vga.getScanLineNumber() < scanLine_18ms); // wait 18ms
  // this may take a couple microseconds, therefore, it may need to reduce 566 to 560 instead...
  // better check all timing with some logic data analyser
  digitalWrtie(DHT11, HIGH);  

  // now start TIMER2 capture, etc.
  Response();
  // at the end of the DHT11 response, disable TIMER2 to stop the screen glitch.

You may get the changes by cloning master branch. downloading the zip file or by pulling from it, using git pull The Zip File with the master branch latest code can be obtained from https://github.com/RoCorbera/BlueVGA/archive/refs/heads/master.zip

Thank you for your patient answer, but I don't know if it is my illusion, it seems to be similar to the tearing caused by using delay(18). Also I added a SSD1306 using hardware I2C1 using U8G2 library. Although they all work fine, but bring a huge moment of tearing, I can only use vga.clearScreen(); to make it black for a moment to increase the degree of smoothness, and if I don't use systick_enable(); Neither will work and I'm depressed.

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

Ok thanks, I'll try it later

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

I tried to put the Timer2 channel1 in OnePulse mode first, and then turn it into capture mode at the end of the pulse, but I searched all afternoon and couldn't find a working code. I don't know how to configure those complicated registers. I don't know why the following code doesn't work.

void Request() /* Microcontroller send request */
{
pinMode(DHT11, PWM);
// digitalWrite(DHT11, LOW);
// delay(18); /* wait for 18ms */

uint16_t pulseDelay = 20000;
uint16_t pulseWidth = 19000;
Timer2.pause(); // stop the timers before configuring them

timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_1, TIMER_OC_PE);

Timer2.setPrescaleFactor(72); // 1 microsecond resolution
Timer2.setOverflow(pulseWidth + pulseDelay-1);
Timer2.setCompare(TIMER_CH1, pulseDelay);

// counter setup in one pulse mode, as slave triggered by External input for Timer 2
TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
TIMER2_BASE->SMCR = ( TIMER_SMCR_TS_ETRF | TIMER_SMCR_SMS_TRIGGER );

TIMER2_BASE->CCER = TIMER_CCER_CC1E ; // enable channels 1
Timer2.attachInterrupt(TIMER_CH1,handler_channel_1);
Timer2.refresh(); // start timer 2
Timer2.resume(); // let timer 2 run
// digitalWrite(DHT11,HIGH); /* set to high pin */
}

void handler_channel_1(void)
{
// turn the timer into capture mode
}

from bluevga.

RoCorbera avatar RoCorbera commented on May 29, 2024

I think that it is very hard to have VGA and anything else that needs specific delay() or Hardware Peripherals runing in the same STM32F103 that will not cause screen tearing.

As I said, 90% of the CPU time is dedicated to generate VGA signals and it depends on the Interrupts, like sendScanLine() working at the exact timing. Otherwise the screen will not be crystal clear.

Given that, the only way to make peripherals (I2C, SPI, PWM, Pulses, UART, etc) to work would be by using pure Hardware and DMA with no Software ISR. The sketch would just check the register status and then process the read data, or fill up SRAM for a DMA to send it to the peripheral.

In this case, no Arduino Library would work as desired and a whole new set of tailor made HAL libraries would be needed.

Other than that, there may be a few possible ways to go:

  1. Create a sort of a synchronous protocol based on SPI to comunicate the STM32F103 VGA device with another STM32 or any other MCU that would actually run all the peripherals and just report back to the STM32 VGA MCU. This would be a dual MCU solution, like a dual Core with a communications channel between them.

  2. Use a monocromatic VGA aproach like those sending SPI pixels in 1bpp. Since this is a more hardware based aproach, it would be better suited for using it at the same time with other Arduino Libraries. It would have a minimal screen tearing, but it will be just one color VGA.
    Check this https://www.artekit.eu/vga-output-using-a-36-pin-stm32/

  3. Move to another MCU such as ESP32, which is dual core and it has a way better bus and set of peripherals that can run in a multimatrix bus. ESP32 has an Arduino VGA Library at https://github.com/bitluni/ESP32Lib

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

I think that it is very hard to have VGA and anything else that needs specific delay() or Hardware Peripherals runing in the same STM32F103 that will not cause screen tearing.

As I said, 90% of the CPU time is dedicated to generate VGA signals and it depends on the Interrupts, like sendScanLine() working at the exact timing. Otherwise the screen will not be crystal clear.

Given that, the only way to make peripherals (I2C, SPI, PWM, Pulses, UART, etc) to work would be by using pure Hardware and DMA with no Software ISR. The sketch would just check the register status and then process the read data, or fill up SRAM for a DMA to send it to the peripheral.

In this case, no Arduino Library would work as desired and a whole new set of tailor made HAL libraries would be needed.

Other than that, there may be a few possible ways to go:

  1. Create a sort of a synchronous protocol based on SPI to comunicate the STM32F103 VGA device with another STM32 or any other MCU that would actually run all the peripherals and just report back to the STM32 VGA MCU. This would be a dual MCU solution, like a dual Core with a communications channel between them.
  2. Use a monocromatic VGA aproach like those sending SPI pixels in 1bpp. Since this is a more hardware based aproach, it would be better suited for using it at the same time with other Arduino Libraries. It would have a minimal screen tearing, but it will be just one color VGA.
    Check this https://www.artekit.eu/vga-output-using-a-36-pin-stm32/
  3. Move to another MCU such as ESP32, which is dual core and it has a way better bus and set of peripherals that can run in a multimatrix bus. ESP32 has an Arduino VGA Library at https://github.com/bitluni/ESP32Lib

Yes, ESP32 has excellent performance and can better complete this project. However, I'm a student and I'm finishing my STM32 course design, and the course is mandated to be done only with STM32 MCU. So I need to connect as many devices as possible to get a higher course score, which is difficult. I went through the code of my DHT11 part yesterday and I think there is no logical problem, but it just doesn't work. I added diagrams in the code comments, I can see from reading your code that your understanding of the MCU is very deep. So can you please help me to check it? Thank you very much.

void Request()      /* Microcontroller send request */
{
  uint16_t PulseLOW = 20000; // should > 18ms
  uint16_t PulseHIGH = 18000; // not important
  
  pinMode(DHT11, PWM);

  Timer2.pause(); // stop the timers before configuring them
  timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_2, TIMER_OC_PE);//set PWM Mode2,and enable
  Timer2.setPrescaleFactor(72); // 1 microsecond resolution
  Timer2.setOverflow(PulseLOW + PulseHIGH-1);
  Timer2.setCompare(TIMER_CH1, PulseLOW);
 // Triggered after PulseLOW
  Timer2.attachInterrupt(TIMER_CH1,Response);
  
  // counter setup in one pulse mode
  TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode

  // as slave triggered by External input for Timer 2,
  //I don't quite understand this sentence and commented it
  //TIMER2_BASE->SMCR = ( TIMER_SMCR_TS_ETRF | TIMER_SMCR_SMS_TRIGGER );
  
  TIMER2_BASE->CCER =  TIMER_CCER_CC1E ; // enable channels 1 
  
  Timer2.refresh(); // start timer 2
  Timer2.resume(); // let timer 2 run

/*
                   Using PWM Mode 2,OnePulse Mode but not work


  _______20MS__________-------------------18MS-------------------___________
  ^                    ^                                         ^
  |<----PulseLOW------>|<-- PulseHIGH, but don't need attention->|      
                       ^
                       |
              Compare1Interrupt
              execution Response(),
           Change the mode of the Timer2

 */

}
 

void Response()
{
    Timer2.detachInterrupt(TIMER_CH1);
    pinMode(DHT11, INPUT_PULLUP);
    Timer2.attachInterrupt(TIMER_CH1,handler_channel_1);
    //Timer2.attachCompare1Interrupt(handler_channel_1);
    TIMER2_BASE->CR1 = TIMER_CR1_CEN;
    TIMER2_BASE->CR2 = 0;
    TIMER2_BASE->SMCR = 0;
    TIMER2_BASE->DIER = TIMER_DIER_CC1IE;
    TIMER2_BASE->EGR = 0;
    TIMER2_BASE->CCMR1 = TIMER_CCMR1_CC1S_INPUT_TI1;
    TIMER2_BASE->CCMR2 = 0;
    TIMER2_BASE->CCER = TIMER_CCER_CC1E;
    TIMER2_BASE->PSC = 71;
    TIMER2_BASE->ARR = 0xFFFF;
    TIMER2_BASE->DCR = 0;
}

void handler_channel_1(void) {                           //This function is called when channel 1 is captured.
    if (0b1 & GPIOA_BASE->IDR  >> 0) {                     //If the receiver channel 1 input pulse on A0 is high.
      channel_1_start = TIMER2_BASE->CCR1;                 //Record the start time of the pulse.
      TIMER2_BASE->CCER |= TIMER_CCER_CC1P;                //Change the input capture mode to the falling edge of the pulse.
    }
    else {                                                 //If the receiver channel 1 input pulse on A0 is low.
      channel_1 = TIMER2_BASE->CCR1 - channel_1_start;     //Calculate the total pulse time.
      if (channel_1 < 0)channel_1 += 0xFFFF;               //If the timer has rolled over a correction is needed.
      TIMER2_BASE->CCER &= ~TIMER_CCER_CC1P;               //Change the input capture mode to the rising edge of the pulse.
      a[index1++]=channel_1;    //Record the duration of the data returned by DHT11 to judge logic 0 and 1, and save it in an array
    }
}

from bluevga.

RoCorbera avatar RoCorbera commented on May 29, 2024

I had to read the Reference Manual and do a lot of experimentation in order to make the Timer1 and Timer4 work as desired.
That was almost 2 years ago and I don't work with STM32 any more.

I can tell that the "recipe" for making One Time Pulse to work is in the page 328 and 329 of the manual

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

I had to read the Reference Manual and do a lot of experimentation in order to make the Timer1 and Timer4 work as desired. That was almost 2 years ago and I don't work with STM32 any more.

I can tell that the "recipe" for making One Time Pulse to work is in the page 328 and 329 of the manual

Thank you, I found the reason, when using DHT11, the pin should be pulled high first pinMode(DHT11, OUTPUT); digitalWrite(DHT11,HIGH);, and then pulled low for 18MS, it is very important! But I delayed with timer and disabled IIC SSD1306, VGA still tearing. I guess the capture mode interrupt of timer2 affects the progress of VGA. The following is the code that can be run,most of them use Timer2 to drive.


void loop()
{
   Request();
 vga.clearScreen(); //swipe the screen to avoid tearing caused by interruption
   vga.waitVSync(3);  // Wait for 3*16MS to receive data
   /*
     Process the received data, then write to VGA
   */
}

void Request()      /* Microcontroller send request */
{

/*Very important!!!!!!!!!!!*/
  pinMode(DHT11, OUTPUT);
  digitalWrite(DHT11,HIGH); 
/*Very important!!!!!!!!!!!*/


  uint16_t PulseLOW = 18000; // should > 18ms
  uint16_t PulseHIGH = 30; // not important
  pinMode(DHT11, PWM);
  Timer2.pause(); // stop the timers before configuring them
  timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_2, TIMER_OC_PE);//set PWM Mode2,and enable
  Timer2.setPrescaleFactor(72); // 1 microsecond resolution
  Timer2.setOverflow(PulseLOW + PulseHIGH-1);
  Timer2.setCompare(TIMER_CH1, PulseLOW);
 // Triggered after PulseLOW
  Timer2.attachInterrupt(TIMER_CH1,Response);
  // counter setup in one pulse mode
  TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
  TIMER2_BASE->CCER =  TIMER_CCER_CC1E ; // enable channels 1 
  Timer2.refresh(); // start timer 2
  Timer2.resume(); // let timer 2 run

/*
                    Using PWM Mode 2

  _______20MS__________-------------------3MS--------------------___________
  ^                    ^                                         ^
  |<----PulseLOW------>|<-- PulseHIGH, but don't need attention->|      
                       ^
                       |
                       
              Compare1Interrupt
              execution Response(),
           Change the mode of the Timer2

 */

}
 

void Response()
{
    Timer2.detachInterrupt(TIMER_CH1);
    pinMode(DHT11, INPUT_PULLUP);
    Timer2.attachInterrupt(TIMER_CH1,handler_channel_1);
    TIMER2_BASE->CCR1=0;
    TIMER2_BASE->CR1 = TIMER_CR1_CEN;
    TIMER2_BASE->CR2 = 0;
    TIMER2_BASE->SMCR = 0;
    TIMER2_BASE->DIER = TIMER_DIER_CC1IE;
    TIMER2_BASE->EGR = 0;
    TIMER2_BASE->CCMR1 = TIMER_CCMR1_CC1S_INPUT_TI1;
    TIMER2_BASE->CCMR2 = 0;
    TIMER2_BASE->CCER = TIMER_CCER_CC1E;
    TIMER2_BASE->PSC = 71;
    TIMER2_BASE->ARR = 0xFFFF;
    TIMER2_BASE->DCR = 0;
}

void handler_channel_1(void) {                           //This function is called when channel 1 is captured.
    if (0b1 & GPIOA_BASE->IDR  >> 0) {                     //If the receiver channel 1 input pulse on A0 is high.
      channel_1_start = TIMER2_BASE->CCR1;                 //Record the start time of the pulse.
      TIMER2_BASE->CCER |= TIMER_CCER_CC1P;                //Change the input capture mode to the falling edge of the pulse.
    }
    else {                                                 //If the receiver channel 1 input pulse on A0 is low.
      channel_1 = TIMER2_BASE->CCR1 - channel_1_start;     //Calculate the total pulse time.
      if (channel_1 < 0)channel_1 += 0xFFFF;               //If the timer has rolled over a correction is needed.
      TIMER2_BASE->CCER &= ~TIMER_CCER_CC1P;               //Change the input capture mode to the rising edge of the pulse.
      DHT11_data[index1++]=channel_1;
    }
}

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

My goodness, what the hell is going on here? ? ? ? Because of debugging, I added a completely unrelated variable, and the code can run completely normally, including DHT11, VGA, everything is as I expected.
But when I want to delete these extraneous variables it doesn't work! ! ! ! I think it must be a matter of metaphysics, and I want to know what's going on? It seems unbelievable, but it happens, I kid you not.

This works perfectly fine!

int32_t channel_1_start, channel_1_stop, channel_1,a=0,b=0,c=0;
//This will also work
int32_t channel_1_start, channel_1_stop, channel_1;
int32_t  a=0,b=0,c=0;
//This will still work as well
int32_t channel_1_start, channel_1_stop, channel_1;
int32_t d=0,e=0,f=0;


void loop(){
};

//*********Even put it here,it still work as well
int32_t d=0,e=0,f=0;

void Request(){
};
void Response(){
};
void handler_channel_1(){
};

But the following code can't drive DHT11 unexpectedly. a, b, c are completely useless variables, I even renamed them to d, e, f and it worked. But I can't delete them because DHT11 will not work properly without them.

//This will not work
int32_t channel_1_start, channel_1_stop, channel_1; //delete abc variable
//This will still not 
int32_t a=0,b=0,c=0;//delete channel variable
//It seems that it will only work if the number of variables is greater than a value

void loop(){
};
void Request(){
};

void Response(){
};
void handler_channel_1(){
};

It seems that it will only work if the number of variables is greater than a value.I can only increase the variable but not decrease it, I try to increase the delay everywhere but it doesn't work, could it be caused by memory.It's like it's kidding me, I can't believe it! Have you ever encountered this problem? Sincerely ask for your advice.

Using the logic analyzer I bought yesterday, I found that it is possible to do PWM all the time to activate the DHT11 without deleting the variable. But once those "useless" variables are deleted, if DHT11 does not respond, it can still generate PWM to generate a low level of 18MS, but once DHT11 responds once, it will never generate PWM again Come to drive DHT11. This is a metaphysical question, very bad.

from bluevga.

RoCorbera avatar RoCorbera commented on May 29, 2024

//*********Even put it here,it still work as well
int32_t d=0,e=0,f=0;

Cortex M3 has some issues with memory fetching time and byte alligment.
This issue you are facing is related to the addressing alligment of the variables.

Some times, in order to reduce the number of cycles for memory fetching and other operations, it is necessary to allign the variables to 32 bits addressing.

Because this VGA driver is very tie in timing, every cycle counts...
Memory allignment reduces the number of cycles used to fetch flash and sram, helping the driver to work better.

Making VGA work correctly in Cortex M3 is not simple.

from bluevga.

kingodragon avatar kingodragon commented on May 29, 2024

I fixed this, because sprintf caused the overflow,but the VGA still tears. The following example can run DHT11 only through Timer2, but still seems to need systick_enable();

uint8_t DHT11=PA0;
uint8_t I_RH,D_RH,I_Temp,D_Temp,CheckSum; 
uint8_t DHT11_data[50]={0},index1=0;
char temp[30]="",hum[30]="";
void setup() {
 // systick_disable();
   Serial2.begin(115200);
   Serial2.println(F("DHTxx test!"));
   pinMode(PB11, OUTPUT);
   print_reg();
}

void loop() {
  // put your main code here, to run repeatedly:
    Timer2.detachInterrupt(TIMER_CH1);
    Request() ;  /* send start pulse */
    delay(200);
    if(index1==41&&((I_RH + D_RH + I_Temp + D_Temp) == CheckSum))
    {
      Receive_data();
      sprintf(temp, "%s%d%c%d %s" , "    ",I_Temp,'.' ,D_Temp,"C"); 
      sprintf(hum, "%s%d%c%d %c    " , "    ",I_RH,'.',D_RH,'%'); 
      Serial2.println(temp);
      Serial2.println(hum);
      Serial2.println("OK");
    }
    else
    {
      Serial2.println("error");
    }
    for(int i=0;i<50;i++)
      DHT11_data[i]=0;
    delay(2000);
    index1=0;
}


void Request()      /* Microcontroller send request */
{
  pinMode(DHT11, OUTPUT);
 // print_reg();
  digitalWrite(DHT11,LOW); 
  uint16_t PulseLOW = 25000; // should > 18ms
  uint16_t PulseHIGH = 30; // not important
  pinMode(DHT11, PWM);
  Timer2.pause(); // stop the timers before configuring them
  timer_oc_set_mode(TIMER2, 1, TIMER_OC_MODE_PWM_2, TIMER_OC_PE);//set PWM Mode2,and enable
  Timer2.setPrescaleFactor(72); // 1 microsecond resolution
  Timer2.setOverflow(PulseLOW + PulseHIGH-1);
  Timer2.setCompare(TIMER_CH1, PulseLOW);
 // Triggered after PulseLOW
  Timer2.attachInterrupt(TIMER_CH1,Response);
  // counter setup in one pulse mode
  //TIMER2_BASE->CR1 = TIMER_CR1_CEN;
  TIMER2_BASE->CR1 = ( TIMER_CR1_OPM ); // one pulse mode
  TIMER2_BASE->CCER =  TIMER_CCER_CC1E ; // enable channels 1 
  Timer2.refresh(); // start timer 2
  Timer2.resume(); // let timer 2 run
  
/*
                    Using PWM Mode 2

  _______20MS__________-------------------18MS-------------------___________
  ^                    ^                                         ^
  |<----PulseLOW------>|<-- PulseHIGH, but don't need attention->|      
                       ^
                       |
                       
              Compare1Interrupt
              execution Response(),
           Change the mode of the Timer2

 */

}
 

void Response()
{
    pinMode(DHT11, INPUT_PULLUP);
    Timer2.pause(); 
    Timer2.attachInterrupt(TIMER_CH1,handler_channel_1);
    TIMER2_BASE->CCR1=0;
    TIMER2_BASE->CR1 = TIMER_CR1_CEN;
    TIMER2_BASE->CR2 = 0;
    TIMER2_BASE->SMCR = 0;
    TIMER2_BASE->DIER = TIMER_DIER_CC1IE ;
    TIMER2_BASE->EGR = 0;
    TIMER2_BASE->CCMR1 = 0b100000001; //Register is set like this due to a bug in the define table (30-09-2017)
    TIMER2_BASE->CCMR2 = 0;
    TIMER2_BASE->CCER = TIMER_CCER_CC1E ;
    TIMER2_BASE->PSC = 71;
    TIMER2_BASE->ARR = 0xFFFF;
}

void print_reg()
{
      Serial2.println("TIMER2_BASE->CR1 ="+ (String)TIMER2_BASE->CR1+';');
      Serial2.println("TIMER2_BASE->CR2 =" +(String)TIMER2_BASE->CR2+';');
      Serial2.println("TIMER2_BASE->SMCR ="+ (String)TIMER2_BASE->SMCR+';');
      Serial2.println("TIMER2_BASE->DIER ="+ (String)TIMER2_BASE->DIER+';') ;
      Serial2.println("TIMER2_BASE->EGR = "+(String)TIMER2_BASE->EGR+';');
      Serial2.println("TIMER2_BASE->CCMR1 = "+(String)TIMER2_BASE->CCMR1+';');
      Serial2.println("TIMER2_BASE->CCMR2 = "+(String)TIMER2_BASE->CCMR2+';');
      Serial2.println("TIMER2_BASE->CCER = "+(String)TIMER2_BASE->CCER+';') ;
      Serial2.println("TIMER2_BASE->PSC = "+(String)TIMER2_BASE->PSC+';');
      Serial2.println("TIMER2_BASE->ARR = "+(String)TIMER2_BASE->ARR+';');
      Serial2.println("TIMER2_BASE->DCR = "+(String)TIMER2_BASE->DCR+';');
      Serial2.println();
}

void handler_channel_1(void) {                           //This function is called when channel 1 is captured.
    if (0b1 & GPIOA_BASE->IDR  >> 0) {                     //If the receiver channel 1 input pulse on A0 is high.
      channel_1_start = TIMER2_BASE->CCR1;                 //Record the start time of the pulse.
      TIMER2_BASE->CCER |= TIMER_CCER_CC1P;                //Change the input capture mode to the falling edge of the pulse.
    }
    else {                                                 //If the receiver channel 1 input pulse on A0 is low.
      channel_1 = TIMER2_BASE->CCR1 - channel_1_start;     //Calculate the total pulse time.
      if (channel_1 < 0)channel_1 += 0xFFFF;               //If the timer has rolled over a correction is needed.
      TIMER2_BASE->CCER &= ~TIMER_CCER_CC1P;               //Change the input capture mode to the rising edge of the pulse.
      DHT11_data[index1++]=channel_1;
      if(index1==41)
        Timer2.detachInterrupt(TIMER_CH1);
    }
}
void Receive_data()    /* Receive data */
{
    int q=0;  
    I_RH=0;
    D_RH=0;
    I_Temp=0;
    D_Temp=0;
    CheckSum=0;
    for (q=1; q<9; q++)
    {
      if(DHT11_data[q]>30)  /* If high pulse is greater than 30ms */
      I_RH = (I_RH<<1)|(0x01);/* Then its logic HIGH */
      else    /* otherwise its logic LOW */
      I_RH = (I_RH<<1);
    }     
    for (q=9; q<17; q++)
    {
      if(DHT11_data[q]>30)  /* If high pulse is greater than 30ms */
      D_RH = (D_RH<<1)|(0x01);/* Then its logic HIGH */
      else    /* otherwise its logic LOW */
      D_RH = (D_RH<<1);
    }   
    for (q=17; q<25; q++)
    {
      if(DHT11_data[q]>30)  /* If high pulse is greater than 30ms */
      I_Temp = (I_Temp<<1)|(0x01);/* Then its logic HIGH */
      else    /* otherwise its logic LOW */
      I_Temp = (I_Temp<<1);
    }
      for (q=25; q<33; q++)
    {
      if(DHT11_data[q]>30)  /* If high pulse is greater than 30ms */
      D_Temp = (D_Temp<<1)|(0x01);/* Then its logic HIGH */
      else    /* otherwise its logic LOW */
      D_Temp = (D_Temp<<1);
    } 
    for (q=33; q<41; q++)
    {
      if(DHT11_data[q]>30)  /* If high pulse is greater than 30ms */
      CheckSum = (CheckSum<<1)|(0x01);/* Then its logic HIGH */
      else    /* otherwise its logic LOW */
      CheckSum = (CheckSum<<1);
    }                                                                                                                                                                       
}

from bluevga.

RoCorbera avatar RoCorbera commented on May 29, 2024

The execution of void handler_channel_1(void) will make the screen tear.
This ISR interferes with the VGA Timer ISR.
Anyway, it has to be done this way, otherwise it would be impossible to read the DHT11 pulses.

Why is it necessary to enable systick? It seems possible to replace all the delay() with some equivalent vga.waitVSync().

Serial2.print() may also create some noise in the screen, but I'm not sure. UART ISR may be used by Arduino Serial and this would also make the screen tear.

from bluevga.

Related Issues (10)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.