#include "Arduino.h" #ifdef __cplusplus extern "C" { #endif #include "mik32_hal_adc.h" #include "mik32_hal_gpio.h" #include "mik32_hal_timer32.h" extern void ErrorMsgHandler(const char * msg); // -------------------------- Analog read -------------------------- // // structure for ADC channel initialization. Only the channel number // changes, everything else is the same static ADC_HandleTypeDef hadc = { .Instance = ANALOG_REG, .Init.EXTClb = ADC_EXTCLB_ADCREF, .Init.EXTRef = ADC_EXTREF_OFF, .Init.Sel = 0 }; // initialize the channel, run a single measurement, wait for the result uint32_t analogRead(uint32_t PinNumber) { uint32_t value = 0; uint32_t adcChannel = analogInputToChannelNumber(PinNumber); if (adcChannel != NC) { // if we use pin A5, we need to set SELA45 (1.15) to 1 to switch the output from A4 to A5 if (PinNumber == A5) { HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_15, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_15, GPIO_PIN_HIGH); } else if(PinNumber == A4) { // return the switch to A4 in case A5 was previously read HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_15, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_15, GPIO_PIN_LOW); } // init channel hadc.Init.Sel = adcChannel; HAL_ADC_Init(&hadc); // start the conversion twice in case another channel was polled before HAL_ADC_SINGLE_AND_SET_CH(hadc.Instance, adcChannel); value = HAL_ADC_WaitAndGetValue(&hadc); HAL_ADC_Single(&hadc); value = HAL_ADC_WaitAndGetValue(&hadc); } else ErrorMsgHandler("analogRead(): invalid analog pin number"); return value; } // -------------------------- Analog write -------------------------- // #define PWM_RESOLUTION_DEFAULT 8 #define WRITE_VAL_MAX_DEFAULT ((1<TimerInstance == TIMER32_0) return HAL_ERROR; // gpio init removed from standard function timerChannel->Instance = (TIMER32_CHANNEL_TypeDef *)&(timerChannel->TimerInstance->CHANNELS[timerChannel->ChannelIndex]); HAL_Timer32_Channel_PWM_Invert_Set(timerChannel, timerChannel->PWM_Invert); HAL_Timer32_Channel_Mode_Set(timerChannel, timerChannel->Mode); HAL_Timer32_Channel_CaptureEdge_Set(timerChannel, timerChannel->CaptureEdge); HAL_Timer32_Channel_OCR_Set(timerChannel, timerChannel->OCR); HAL_Timer32_Channel_ICR_Clear(timerChannel); HAL_Timer32_Channel_Noise_Set(timerChannel, timerChannel->Noise); return HAL_OK; } /* It is recommended to enable the timer in the following order: - Set the required operating mode. In the INT_MASK register 0; - Write 0xFFFFFFFF to the INT_CLEAR register; - Set TIM_EN to 1; - If you need interrupts from the timer, set the required interrupt mask in the INT_MASK register. */ void analogWrite(uint32_t PinNumber, uint32_t writeVal) { if (digitalPinHasPWM(PinNumber)) { if (writeVal > WriteValMax) writeVal = WriteValMax; // initialization of the required timer htimer32.Instance = pwmPinToTimer(PinNumber); htimer32.Top = pwmTopVal; htimer32.State = TIMER32_STATE_DISABLE; htimer32.Clock.Source = TIMER32_SOURCE_PRESCALER; htimer32.Clock.Prescaler = 0; // Prescaler = 1 htimer32.InterruptMask = 0; htimer32.CountMode = TIMER32_COUNTMODE_FORWARD; HAL_Timer32_Init(&htimer32); // gpio init as timer channel pin HAL_GPIO_PinConfig(digitalPinToPort(PinNumber), digitalPinToBitMask(PinNumber), HAL_GPIO_MODE_TIMER_SERIAL, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); htimer32_channel.TimerInstance = htimer32.Instance; htimer32_channel.ChannelIndex = pwmPinToTimerChannel(PinNumber); htimer32_channel.PWM_Invert = TIMER32_CHANNEL_NON_INVERTED_PWM; htimer32_channel.Mode = TIMER32_CHANNEL_MODE_PWM; htimer32_channel.CaptureEdge = TIMER32_CHANNEL_CAPTUREEDGE_RISING; // cast to uint64_t to avoid overflow when multiplying htimer32_channel.OCR = (uint32_t) (((uint64_t)pwmTopVal * writeVal) / WriteValMax); htimer32_channel.Noise = TIMER32_CHANNEL_FILTER_OFF; Timer32_Channel_Init(&htimer32_channel); // start timer with initialized channel HAL_Timer32_Channel_Enable(&htimer32_channel); HAL_Timer32_Value_Clear(&htimer32); HAL_Timer32_Start(&htimer32); pwmIsInited = true; // if at least one channel is working, say that the module is initialized } else if(PinNumber == 10) // pin d10 has pwm, but you cannot use it while spi is running ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running"); else ErrorMsgHandler("analogWrite(): invalid pwm pin number"); } // Set the resolution of analogWrite parameters void analogWriteResolution(uint8_t resolution) { if ((resolution > 0) && (resolution < 32)) WriteValMax = (1 << resolution) - 1; else if (resolution == 32) WriteValMax = UINT32_MAX; else ErrorMsgHandler("analogWriteResolution(): invalid resolution"); } // Set the frequency of analogWrite void analogWriteFrequency(uint32_t freq) { if ((freq >= 1) && (freq <= PWM_FREQUENCY_MAX)) pwmTopVal = F_CPU/freq; else ErrorMsgHandler("analogWriteFrequency(): invalid frequency"); } /* It is recommended to turn off the timer in the following order: - Write 0 to the INT_MASK register; - Write 0 to the TIM_PRESCALE register; - Write 0 to the INT_CLEAR register; - Set TIM_EN to 0. */ void analogWriteStop(uint32_t PinNumber) { if (pwmIsInited) { // load the timer address and channel number corresponding to the specified pin htimer32.Instance = pwmPinToTimer(PinNumber); htimer32_channel.TimerInstance = htimer32.Instance; htimer32_channel.ChannelIndex = pwmPinToTimerChannel(PinNumber); // in the initChannel function they do it inside, but in deinit they don't. We do it outside htimer32_channel.Instance = (TIMER32_CHANNEL_TypeDef *)&(htimer32_channel.TimerInstance->CHANNELS[htimer32_channel.ChannelIndex]); // и все чистим/отключаем HAL_Timer32_InterruptMask_Clear(&htimer32, 0xFFFFFFFF); HAL_Timer32_Prescaler_Set(&htimer32, 0); HAL_Timer32_InterruptFlags_ClearMask(&htimer32, 0xFFFFFFFF); HAL_Timer32_Channel_DeInit(&htimer32_channel); HAL_Timer32_Stop(&htimer32); pwmIsInited = false; } } #ifdef __cplusplus } #endif