I have a macbookpro11,3 without a battery. When battery is removed the firmware throttles the CPU to half speed. In Windows I can override this using Throttlestop to turn off BD PROCHOT and set multiplier to 25. I want to do this from EFI so that boot and updates run at a normal speed.
Based on source for rEFInd which updates 0x3a register I wrote this program but while BD PROCHOT is disabled correctly after booting into Windows the multiplier is not.
#include "../include/tiano_includes.h"
static VOID DisablePROCHOT(VOID)
{
UINT32 msr = 0x1FC;
UINT32 low_bits = 0, high_bits = 0;
__asm__ volatile ("rdmsr" : "=a" (low_bits), "=d" (high_bits) : "c" (msr));
// lowest bit is BD PROCHOT
low_bits &= ~(1 << 0);
__asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits));
} // VOID DisablePROCHOT()
static VOID SetMultiplier25(VOID)
{
UINT32 msr = 0x199;
UINT32 low_bits = 0, high_bits = 0;
__asm__ volatile ("rdmsr" : "=a" (low_bits), "=d" (high_bits) : "c" (msr));
// second lowest byte is multiplier
// 25 is .... xxxxxxxx 00011001 xxxxxxxx
low_bits |= 1 << 8;
low_bits &= ~(1 << 9);
low_bits &= ~(1 << 10);
low_bits |= 1 << 11;
low_bits |= 1 << 12;
low_bits &= ~(1 << 13);
low_bits &= ~(1 << 14);
low_bits &= ~(1 << 15);
__asm__ volatile ("wrmsr" : : "c" (msr), "a" (low_bits), "d" (high_bits));
} // VOID SetMultiplier25()
EFI_STATUS
EFIAPI
efi_main (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
DisablePROCHOT();
SetMultiplier25();
return EFI_SUCCESS;
}
Reading the registers with rdmsr from EFI appears to show both are set correctly however when booted into Windows while bit 0 of 0x1FC is correctly set off the multiplier stored in 0x199 is unchanged from the default of 12 when I expect it to be 25.
Default values
These are values after standard boot into Windows (from RWEverything)
Results after calling program
Program was called from EFI shell before calling Windows boot loader bootmgfw.efi
0x1FC is updated, 0x199 is not.
Updating 0x199 with RWEverything from within Windows changes the multiplier correctly so I'm fairly sure it is the correct register.
As this is my first EFI (or C) program I may have overlooked something trivial.
You have to create a loop and change processor affinity each time through the loop. Then you do a wrmsr for each thread (CPU1, CPU2, CPU3, CPU4) each time through the loop. In Windows you use this function.
https://learn.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-setthreadaffinitymask
As soon as you boot up, Windows changes the values in MSR 0x199 so seeing what values are in MSR 0x199 after you boot up does not prove anything.
To simplify things, you can do this in SetMultiplier,
low_bits = 0x1900
Related
I am writing code for the STM32F031K6T6 MCU using the Keil uVision. The IDE information is shown in the image below:
enter image description here
The C/C++ options for Target are configured as shown here:
enter image description here
I started a new project, selected the chip, and configured the run-time environment as below:
enter image description here
I initialized the clock and configured the Flash registers for the appropriate latency. I tested the frequency using MCO and it seems correct. I also initialized some GPIOs, UART, and the SysTick. The peripheral registered is modified as expected as seen on the System View for the respective peripheral in the debugging mode.
The problem is that some functions, such as functions for sending and receiving data via UART and some functions that use GPIO ports only work in debugging mode when I run the code line-by-line. If I click the run button the code gets stuck and the chip stops responding. I still see the VAL and CURRENT registers of the SysTick updating.
This is an example of a function that works:
void System_Clock_init(void){
FLASH->ACR &= ~FLASH_ACR_LATENCY;
FLASH->ACR |= FLASH_ACR_LATENCY | 0x01;
RCC->CR |= RCC_CR_HSION;
while((RCC->CR & RCC_CR_HSIRDY) == 0);
RCC->CR &= ~RCC_CR_HSITRIM;
RCC->CR |= 16UL << 3;
RCC->CR &= ~RCC_CR_PLLON;
while((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY);
RCC->CFGR &= ~RCC_CFGR_PLLSRC;
RCC->CFGR |= 10UL << 18;
RCC->CFGR &= ~RCC_CFGR_HPRE;
RCC->CFGR &= ~RCC_CFGR_PPRE;
RCC->CR |= RCC_CR_PLLON;
while((RCC->CR & RCC_CR_PLLRDY) == 0);
RCC->CFGR &= ~RCC_CFGR_SW;
RCC->CFGR |= RCC_CFGR_SW_PLL;
while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL);
}
This is an example of a function that doesn’t work:
void UV_LED_Driver(uint32_t d){
for(uint32_t i = 0; i<16; i++){
if(d&(((uint32_t)0x8000)>>i)){
SDI2_ON;
}
else {
SDI2_OFF;
}
CLK2
}
LATCH2
}
The macros used in the function above are defined as below:
// CLK2 -> PA5
// LE2 -> PA4
// SDI2 -> PA6
#define CLK2_OFF GPIOA->ODR |= (1UL << 5)
#define CLK2_ON GPIOA->ODR &= ~(1UL << 5)
#define LE2_OFF GPIOA->ODR |= (1UL << 4)
#define LE2_ON GPIOA->ODR &= ~(1UL << 4)
#define SDI2_ON GPIOA->ODR &= ~(1UL << 6)
#define SDI2_OFF GPIOA->ODR |= (1UL << 6)
#define CLK2 {CLK2_ON; us_Delay(1); CLK2_OFF;}
#define LATCH2 {LE2_ON; us_Delay(1); LE2_OFF;}
The GPIO pins used in the function above are initialized as follows:
// CLK2 -> PA5
// LE2 -> PA4
// SDI2 -> PA6
void UV_LED_Driver_Init(void){
RCC->AHBENR |= RCC_AHBENR_GPIOAEN;
GPIOA->MODER &= ~((3UL << 8) | (3UL << 10) | (3UL << 12));
GPIOA->MODER |= ((1UL << 8) | (1UL << 10) | (1UL << 12));
GPIOA->OTYPER &= ~(0x70UL);
GPIOA->PUPDR &= ~((1UL << 8) | (1UL << 10) | (1UL << 12));
GPIOA->OSPEEDR &= ~((3UL << 8) | (3UL << 10) | (3UL << 12));
GPIOA->OSPEEDR |= ((1UL << 8) | (1UL << 10) | (1UL << 12));
GPIOA->ODR |= (0x70UL);
}
And the us_Delay() function is based on SysTick. These are defined as:
static uint32_t usDelay = 0;
void SysTick_init(uint32_t ticks){
SysTick->CTRL = 0;
SysTick->LOAD = ticks - 1;
NVIC_SetPriority(SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);
SysTick->VAL = 0;
SysTick->CTRL |= SysTick_CTRL_CLKSOURCE_Msk;
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Handler(void){
if(usDelay > 0){
usDelay--;
}
}
void us_Delay(uint32_t us){
usDelay = us;
while(usDelay != 0);
}
Now, this is the same UV_LED_Driver(uint32_t d) function defined as a macro (Runs as expected):
#define UV_LED_DRIVER(d) {for(int i = 0; i<16; i++){if(d&(0x000F>>i)){SDI2_ON;}else {SDI2_OFF;}CLK2}LATCH2}
This is the main():
#include <stm32f031x6.h>
#include "clock.h"
#include "LED_Driver.h"
#include "UART.h"
int main(void){
System_Clock_init();
Color_LED_Driver_Init();
UV_LED_Driver_Init();
Nucleo_Green_LED_Init();
UART_init();
SysTick_init(47);
//MCO_Init(); // Check PIN 18 (PA8) for the frequency of the MCO using an Oscilloscope
while(1){
UV_LED_DRIVER(~(0x0000)) // This runs well
//UV_LED_Driver((uint32_t)~(0x0000)); // If I run this line
//the debugger gets stuck here. It works if I run line-by-line
ms_Delay(100);
UV_LED_DRIVER(~(0xFFFF)) // This runs well
//UV_LED_Driver((uint32_t)~(0xFFFF)); // If I run this line
//the debugger gets stuck here. It works if I run line-by-line
ms_Delay(100);
}
}
Interestingly, if I define the functions as macros, they behave as desired. I finally tested the code on a STM32F429ZIT chip and it worked well, given the needed modifications in the initialization of the main clock and the GPIO.
Has anyone ever experienced anything similar or happens to know what could be causing this issue? I know that I could walk around this issue using CubeMX but I would like to find out what is causing this problem.
Thank you.
I asked the same question at the ST Community forum and the user waclawek.jan answered it. The problem is that I was calling the SysTick interrupt too often, not leaving any time for the main() to run. To fix the code, I just called the SysTick_init() function passing "479" as an argument instead of "47".
Thank you!
I have the assignment to create a running light on my Arduino with the following requirements/constraints
Requirements
Implement a socalled “runninglight” with 3 leds.
The on time of each led is the same, being 0.5 sec.
After the last Led is lit, the first starts again.
Constraints
The leds are connected to pin 8,9 and 10 of the Arduino. (don’t forget the resistors)
The running led must be implemented in the loop of the Arduino
The setup() function may contain any Arduino function/macro.
Only the Arduino function delay() is allowed in the loop.
No use of any other Arduino function/macro etc. in the loop.
No use of for/while in the loop() function
No use of your own defined functions
Your loop function must contain not more then 10 statements.
So in the loop you may only use
o Delay function
o Your variables
o The following characters/digits: * ( ) & ~ | ; = < > ! + - 0 1 2 3 4 5 6 7 8 9
I have tried the following code
#include <Arduino.h>
//mask for setting correct bits in register to setup leds to 1
#define DDBMASK 0x07
//masks for setting correct bits in register for led control to 1
#define LEDMASK 0x01
byte *ddBPtr; //point to ddB register (data direction)
byte *portBPtr; //point to portB resiger (data register)
void setup() {
//setup data direction register to set pins to output
ddBPtr = (byte *) 0x24;
*ddBPtr |= DDBMASK; // 0b0000 0111
//assign pointer to right register
portBPtr = (byte *) 0x25;
}
void loop() {
//use data register (portB) for controlling leds
*portBPtr ^= LEDMASK;
delay(500);
*portBPtr ^= LEDMASK;
*portBPtr ^= LEDMASK << 1;
delay(500);
*portBPtr ^= LEDMASK << 1;
*portBPtr ^= LEDMASK << 2;
delay(500);
*portBPtr ^= LEDMASK << 2;
}
Apparently this is possible with only one delay function and following the requirements and constrains. I have been stuck on this for hours and cant figure it out.
I tried the following which also does not work because I'm unable to reset my counter back to zero
void loop() {
//use data register (portB) for controlling leds
*portBPtr ^= (LEDMASK << ledCount);
delay(500);
*portBPtr ^= (LEDMASK << ledCount);
ledCount++;
//cant figure out a way to reset ledCount back to 0 after 3 itterations
//running light only runs once so first led does not light after third led is lit
}
What am I missing?
Perhaps this:
*portBPtr |= (1 << ledCount);
delay(500);
*portBPtr &= ~(1 << ledCount);
ledCount = (9 >> (ledCount << 1)) & 3;
This also avoids ^ which is not in your list of allowed symbols.
The line ledCount = (9 >> (ledCount << 1)) & 3 is like a lookup table with each entry taking up two bits. It maps 0 to 1, 1 to 2, 2 to 0. The normal way to write this code is ledCount = (1 + ledCount) % 3;
This might also work, being a little simpler:
delay(500);
*portBPtr = (1 << ledCount);
ledCount = (9 >> (ledCount << 1)) & 3;
By using assignment rather than | or & or ^, all the other bits will be zero, presumably causing the non-current leds to turn off.
I am new to AVR programming, so sorry if question is trivial.
Using :
OS : Windows7
IDE : Atmel studio
uC = m328p
Pins:
ADC signal - ADC0/PC0
LED_values - (PB0 - PB7)
LED_START - PD1
LED_LIGHT - PD0
BUTTON - PD2
Goal: When you press the button it turns On the LED_START and it needs to start with conversion.
AVR gets interrupt and starts ADC conversion. Basically program has two interrupts. I know that INT0 interrupt has highest priority.
I dont know how to deal with them.
I have tried several things like adding global variable "start" and changing it. And also when i only set LED START it turns On and it stays in that state until LED_values reach certain value, then LED START turns Off by it self.
So please can you show me how to handle two interrupts so that fulfills stated goal and explain me what im doing wrong.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
#define BIT_IS_SET(byte, bit) (byte & (1 << bit))
#define BIT_IS_CLEAR(byte, bit) (!(byte & (1 << bit)))
typedef enum{false, true} bool;
bool previousState = false;
bool start = false;
char num;
void setup();
void loop();
void ADC_init();
void EI_init(); // External Interrupt
int main(void)
{
setup();
loop();
}
void setup(){
DDRC &= ~(0x1); // LDR Input
DDRB = 0xFF; //LEDs value Output
DDRD |= 0x3; //LED light LED start Output
DDRD &= ~(1 << PIND2); //Button Input
}
void loop(){
PORTD |= (1 << PIND2);
EI_init();
ADC_init();
sei();
if(start){
ADCSRA |= (1 << ADSC);
}
while(1){}
}
void ADC_init(){
ADMUX = 0x60;
ADCSRA = 0x8B;
ADCSRB = 0x0;
ADCH = 0x0;
}
ISR(ADC_vect) {
PORTB = ADCH; // assign contents of ADC high register to Port D pins
int b = (int)ADCH;
if(b > 180) { //100
PORTD = 0x1;
}else{
PORTD &= ~(0x1);
}
_delay_ms(100);
ADCSRA |= (1 << ADSC); // start next ADC
}
void EI_init(){
EIMSK |= (1 << INT0); // Interrupt enabled
EICRA |= (1 << ISC00); // any state change
}
ISR(INT0_vect){
if(BIT_IS_CLEAR(PORTD,PIND2)){
start = true;
}else{
start = false;
}
}
Here is scheme : scheme
First of all, you should make start be volatile since it is being used by both the main loop and the interrupt. The volatile keyword tells the compiler that the variable might be modified by things outside of its control, so it cannot optimize away any reads or writes to the variable:
volatile bool start = false;
Secondly, you probably want to remove this line you wrote at the end of loop:
while(1){}
That line is bad because it causes your program to go into an infinite loop where it does nothing. I think you actually want the code you wrote about it in the loop function to run multiple times.
Secondly, after you detect that the start flag has been set, you probably need to set it to 0, or else it will just be 1 forever.
Third, setting start to false in the INT0 ISR might be a bad idea, because it might get set to false before you main loop has a chance to observe it being true and handle the event. I guess it really depends on exactly what you are trying to do. You could try adding details to your question about exactly what problem you are trying to solve using the AVR. See What is the XY problem?.
There are probably other issues with your code that need to be debugged. Can you think of any ways to make this simpler? Maybe you can reduce the number of interrupts you are using. To debug, you can try blinking some LEDs to figure out what parts of your program are executing.
I wrote some simple code where I am using the timer1 on my Arduino Uno. The problem is I can't stop the timer any way I try.
I am using this program to count and show on the display the number of external interrupts on pin 2 while measuring the time. But when I press button fin I want to stop generating interrupts for the program which is increasing the variable time called cas. Can you help somehow, please?
My code:
#include <OLED_I2C.h>
#define alarm_output 10
#define fin 13
int suma=0;
int alarm=0;
float cas=0;
OLED myOLED(SDA, SCL, 8);
extern uint8_t MediumNumbers[];
extern uint8_t BigNumbers[];
extern uint8_t SmallFont[];
void setup(void) {
pinMode(alarm_output,OUTPUT);
digitalWrite(alarm_output,LOW);
pinMode(fin,INPUT_PULLUP);
pinMode(9,INPUT_PULLUP);
//interrupt
interrupts();
attachInterrupt(digitalPinToInterrupt(2), displej, CHANGE);
//first screen
myOLED.begin();
myOLED.setFont(SmallFont);
myOLED.print("TIME:", 0, 30);
myOLED.print("INTERRUPT:", 0, 56);
myOLED.print("Laser game", CENTER, 0);
myOLED.setFont(MediumNumbers);
myOLED.printNumF(cas,1,RIGHT,20);
myOLED.setFont(BigNumbers);
myOLED.printNumI(suma, RIGHT, 40);
myOLED.update();
//start loop
up:;
if(digitalRead(9)==1)
goto up;
// TIMER 1 for interrupt frequency 10 Hz:
cli(); // stop interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 10 Hz increments
OCR1A = 24999; // = 16000000 / (64 * 10) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
}
void displej(){
suma++;
alarm=3;
}
ISR(TIMER1_COMPA_vect){
cas=cas+0.1;
if(alarm>0)
alarm--;
}
void loop(void) {
myOLED.setFont(MediumNumbers);
myOLED.printNumF(cas,1,RIGHT,20);
myOLED.setFont(BigNumbers);
myOLED.printNumI(suma, RIGHT, 40);
myOLED.update();
if(digitalRead(fin)==0){
cli();
TCCR1B |= (0 << CS12) | (0 << CS11) | (0 << CS10); //this do now work
detachInterrupt(digitalPinToInterrupt(2));
sei();
}
if(alarm>0)
digitalWrite(alarm_output,HIGH);
else
digitalWrite(alarm_output,LOW);
delay(10);
}
I've tested all three methods for "turning off the timer." Just comment out the one you prefer in the code below to see it demonstrated. All three are effective at getting the Arduino's LED to quit blinking.
void setup(void) {
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
interrupts();
// TIMER 1 for interrupt frequency 10 Hz:
cli(); // stop interrupts
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// set compare match register for 10 Hz increments
OCR1A = 24999; // 200 millisecond cycle
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS12, CS11 and CS10 bits for 64 prescaler
TCCR1B |= (0 << CS12) | (1 << CS11) | (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei(); // allow interrupts
}
volatile uint8_t count = 0;
volatile uint8_t timer_flip = 0;
ISR(TIMER1_COMPA_vect){
if (timer_flip == 0)
timer_flip = 1;
else
timer_flip = 0;
if (timer_flip == 1)
digitalWrite(13, HIGH);
else
digitalWrite(13, LOW);
count++;
}
void loop(void)
{
if (count > 100) // runs for a few seconds
{
//cli(); // One way to disable the timer, and all interrupts
//TCCR1B &= ~(1<< CS12); // turn off the clock altogether
//TCCR1B &= ~(1<< CS11);
//TCCR1B &= ~(1<< CS10);
//TIMSK1 &= ~(1 << OCIE1A); // turn off the timer interrupt
}
}
This exact code is running on an Uno right beside me now. I've tested all three "turn off" mechanisms above and they all work.
To make a minimal, verifiable example I stripped out all the OLED stuff. I changed pin 13 to an output and set it to blink the LED while it could (and when it stops the timers and/or interrupts are clearly disabled).
A couple of learning points:
You should not use pin 13 for your "fin" button without additional circuitry -- see this Arduino official reference.
You should declare as volatile any variable that is written to in your interrupt service routines.
Your choice of which method to turn off the timer depends on your goal. You just disable the timer interrupt, disable all interrupts, or simply turn the clock source off. The choice is yours.
Sure thing! There are two ways you can do it. You can simply stop the timer interrupt but leave the timer running using:
TIMSK1 &= ~(1 << OCIE1A);
Or, you can stop the timer altogether by altering the clock source to "none" like:
TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10));
which effectively undoes what you did to select the clock source in the first place. After this the CS12-CS11-CS10 bits will be 0-0-0 and the clock source will be stopped. See p. 134 of the datasheet.
this is my code
#include "LPC17xx.h" // Device header
#include "GPIO_LPC17xx.h" // Keil::Device:GPIO
uint32_t voltag1 = 0 ;
uint32_t voltag2 = 0 ;
volatile uint32_t adstat;
int blink=1;
int main()
{
//Config timer
LPC_TIM1->MCR=2;
LPC_TIM1->MR0=20000000; //Match Resgister
LPC_TIM1->TCR=1;
LPC_TIM1->EMR = 0x00000030 ;
//Config ADC
LPC_PINCON->PINSEL1 |= (1 << 14) | (1 << 16); // connect pin to ADC
LPC_SC->PCONP |= ((1 << 12)); //enable power of ADC
LPC_ADC->ADCR = 0x06202001; //initialaze ADC
LPC_ADC->ADINTEN = 0x00000100; // global interup
NVIC_EnableIRQ(ADC_IRQn);
GPIO_SetDir(3,25,GPIO_DIR_OUTPUT);
while(1) {}
}
void ADC_IRQHandler(void)
{
adstat = LPC_ADC->ADSTAT; /* Read ADC clears interrupt */
blink++;
GPIO_PinWrite(3,25,blink%2);
voltag1 = (LPC_ADC->ADGDR >> 4) & 0xFFF;
//voltag2 = (LPC_ADC->ADDR1 >> 4) & 0xFFF;
}
when i use LPC_ADC->ADGDR it work fine but when i use LPC_ADC->ADDR1 its not working , why?
i used MAT for ADC interup
and when i use LPC_ADC->ADGDR everything works fine
but when i use LPC_ADC->ADDR1 for reading its not working and not change with MAT edge
There are way too many magic numbers in your code. Please use the corresponding defines for all those bits. This code is unreadable as is.
There is a wrong comment in your code, the interrupt flag for ADGDR is not cleared on ADSTAT read. Only a read of ADGDR clears it, and thats why your code does not work with ADDR1.
Had you used the definition to set ADINTEN, you might have spotted your error sooner. That flag is named ADGDINTEN and corresponds to the flag in ADGDR only.
You should enable IRQ of ch1 by:
LPC_ADC->ADINTEN = 1 << 1; //0x0002