dev0.2_halRevision (#1)

- Реализация части функций в библиотеках hal перенесена в заголовочный файл, функции определены как inline.
- В модулях Tone, SPI, Wire работа с регистрами вынесена в библиотеку hal или в платозависимые файлы pins_arduino.h, variants.c
- В модуле wiring_analog при отключении работы ШИМ сначала проверяется, включен ли ШИМ на указанной ноге. Если включен, вывод после отключения таймера конфигурируется на вход.

Reviewed-on: Elron_dev/elbear_arduino_bsp#1
This commit is contained in:
klassents 2024-09-11 10:50:22 +03:00
parent f020720e1f
commit 8f0a5b0a94
17 changed files with 433 additions and 313 deletions

3
.gitignore vendored
View File

@ -1 +1,2 @@
installed.json installed.json
.vscode/

View File

@ -100,7 +100,7 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration)
HAL_EPIC_MaskLevelSet(HAL_EPIC_TIMER16_1_MASK); HAL_EPIC_MaskLevelSet(HAL_EPIC_TIMER16_1_MASK);
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
timer_pin_port->CLEAR = timer_pin_mask; HAL_GPIO_WritePin((GPIO_TypeDef *)timer_pin_port, timer_pin_mask, GPIO_PIN_LOW);
HAL_Timer16_Counter_Start_IT(&htimer16_1, frequencyParams.period_ticks); HAL_Timer16_Counter_Start_IT(&htimer16_1, frequencyParams.period_ticks);
timerIsOn = true; timerIsOn = true;
@ -124,8 +124,9 @@ void noTone(uint8_t pin)
{ {
if (timerIsOn) if (timerIsOn)
{ {
timer_pin_port->CLEAR = timer_pin_mask; // pin to 0 // pin to 0
htimer16_1.Instance->CR &= ~TIMER16_CR_ENABLE_M; // disable timer HAL_GPIO_WritePin((GPIO_TypeDef *)timer_pin_port, timer_pin_mask, GPIO_PIN_LOW);
HAL_Timer16_Disable(&htimer16_1); // disable timer
HAL_EPIC_MaskLevelClear(HAL_EPIC_TIMER16_1_MASK); HAL_EPIC_MaskLevelClear(HAL_EPIC_TIMER16_1_MASK);
pinMode(pin, INPUT); // deinit pin pinMode(pin, INPUT); // deinit pin
timer_pin = -1; // reset to default timer_pin = -1; // reset to default
@ -136,12 +137,12 @@ void noTone(uint8_t pin)
// irq handler // irq handler
extern "C" void tone_interrupt_handler(void) extern "C" void tone_interrupt_handler(void)
{ {
if ((htimer16_1.Instance->ISR & htimer16_1.Instance->IER) & TIMER16_ISR_ARR_MATCH_M) if(HAL_Timer16_GetInterruptStatus_ARRM(&htimer16_1))
{ {
// timer period has passed, change the pin state // timer period has passed, change the pin state
if (timer_toggle_count != 0) if (timer_toggle_count != 0)
{ {
timer_pin_port->OUTPUT_ ^= timer_pin_mask; HAL_GPIO_TogglePin((GPIO_TypeDef*)timer_pin_port, timer_pin_mask);
if (timer_toggle_count > 0) if (timer_toggle_count > 0)
timer_toggle_count--; timer_toggle_count--;
@ -149,10 +150,10 @@ extern "C" void tone_interrupt_handler(void)
else else
{ {
// turn off if the specified duration has passed // turn off if the specified duration has passed
timer_pin_port->CLEAR = timer_pin_mask; HAL_GPIO_WritePin((GPIO_TypeDef *)timer_pin_port, timer_pin_mask, GPIO_PIN_LOW);
noTone(timer_pin); noTone(timer_pin);
} }
} }
// reset timer interrupt flags // reset timer interrupt flags
htimer16_1.Instance->ICR = 0xFFFFFFFF; HAL_Timer16_ClearInterruptMask(&htimer16_1, 0xFFFFFFFF);
} }

View File

@ -375,14 +375,96 @@ typedef enum __HAL_GPIO_InterruptMode
HAL_StatusTypeDef HAL_GPIO_Init(GPIO_TypeDef *GPIO_x, GPIO_InitTypeDef *GPIO_Init); HAL_StatusTypeDef HAL_GPIO_Init(GPIO_TypeDef *GPIO_x, GPIO_InitTypeDef *GPIO_Init);
HAL_StatusTypeDef HAL_GPIO_PinConfig(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin, HAL_GPIO_ModeTypeDef mode, HAL_GPIO_PullTypeDef pull, HAL_GPIO_DSTypeDef driveStrength); HAL_StatusTypeDef HAL_GPIO_PinConfig(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin, HAL_GPIO_ModeTypeDef mode, HAL_GPIO_PullTypeDef pull, HAL_GPIO_DSTypeDef driveStrength);
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin);
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin, GPIO_PinState pinState);
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin);
HAL_StatusTypeDef HAL_GPIO_InitInterruptLine(HAL_GPIO_Line_Config mux, HAL_GPIO_InterruptMode mode); HAL_StatusTypeDef HAL_GPIO_InitInterruptLine(HAL_GPIO_Line_Config mux, HAL_GPIO_InterruptMode mode);
HAL_StatusTypeDef HAL_GPIO_DeInitInterruptLine(HAL_GPIO_Line irqLine); HAL_StatusTypeDef HAL_GPIO_DeInitInterruptLine(HAL_GPIO_Line irqLine);
uint32_t HAL_GPIO_LineInterruptState(HAL_GPIO_Line irqLine);
GPIO_PinState HAL_GPIO_LinePinState(HAL_GPIO_Line irqLine); /**
void HAL_GPIO_ClearInterrupts(); * @brief Считать текущее состояние выводов порта GPIO_x.
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска выводов порта GPIO_x, с которых считывание значение.
* @return @ref GPIO_PIN_HIGH если с одного или больше выводов, указанных в pin, считалась 1. Иначе @ref GPIO_PIN_LOW.
*/
static inline __attribute__((always_inline)) GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin)
{
if ((GPIO_x->SET & pin) != (uint32_t)GPIO_PIN_LOW)
return GPIO_PIN_HIGH;
else
return GPIO_PIN_LOW;
}
/**
* @brief Задать логический уровень выходного сигнала для указанных выводов порта GPIO_x.
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска выводов порта GPIO_x, к которым применяются указанные настройки.
* @param pinState значение состояние вывода, в которое будут установлены указанные выводы.
* Этот параметр должен быть одним из значений:
* - @ref GPIO_PIN_LOW низкий выходной уровень
* - @ref GPIO_PIN_HIGH высокий выходной уровень
*/
static inline __attribute__((always_inline)) void HAL_GPIO_WritePin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin, GPIO_PinState pinState)
{
if (pinState == GPIO_PIN_LOW)
GPIO_x->CLEAR = pin;
else
GPIO_x->SET = pin;
}
/**
* @brief Переключить логический уровень выходного сигнала для указанных выводов порта GPIO_x.
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска выводов порта GPIO_x, к которым применяются указанные настройки.
*/
static inline __attribute__((always_inline)) void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin)
{
GPIO_x->OUTPUT_ ^= pin;
}
/**
* @brief Возвращает направление вывода при работе в режиме вход/выход
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска вывода порта GPIO_x, направление которого необходимо узнать.
* @return Возвращает направление вывода - input или output.
*/
static inline __attribute__((always_inline)) HAL_GPIO_ModeTypeDef HAL_GPIO_GetPinDirection(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin)
{
return (GPIO_x->DIRECTION_IN & pin) == 0 ? HAL_GPIO_MODE_GPIO_OUTPUT : HAL_GPIO_MODE_GPIO_INPUT;
}
/**
* @brief Получить состояние линии прерывания.
* @param irqLine номер линии прерывания.
* @return Возвращает 1 если сработало прерывание данной линии, иначе 0.
*/
static inline __attribute__((always_inline)) uint32_t HAL_GPIO_LineInterruptState(HAL_GPIO_Line irqLine)
{
int irq_line_num = irqLine >> GPIO_IRQ_LINE_S;
return (GPIO_IRQ->INTERRUPT & (1 << (irq_line_num))) != 0;
}
/**
* @brief Функция чтения логического уровня вывода, подключенного к линии прерывания.
* @param irqLine номер линии прерывания.
* @return Логический уровень вывода.
*/
static inline __attribute__((always_inline)) GPIO_PinState HAL_GPIO_LinePinState(HAL_GPIO_Line irqLine)
{
int irq_line_num = irqLine >> GPIO_IRQ_LINE_S;
return (GPIO_PinState)((GPIO_IRQ->STATE & (1 << (irq_line_num))) >> irq_line_num);
}
/**
* @brief Функция сброса регистра состояния прерываний.
* @note Когда срабатывает прерывание на одной из линии, в регистре INTERRUPT
* выставляется 1 в разряде, соответствующем линии прерывания.
* После обработки прерывания необходимо сбросить данный регистр
* в обработчике прерывания trap_handler().
* Если после обработки прерывания регистр не был сброшен,
* обработчик будет вызван снова, программа будет бесконечно вызывать обработчик.
*/
static inline __attribute__((always_inline)) void HAL_GPIO_ClearInterrupts()
{
GPIO_IRQ->CLEAR = 0b11111111;
}
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -380,9 +380,6 @@ typedef struct
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c); void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c);
void HAL_I2C_Disable(I2C_HandleTypeDef *hi2c);
void HAL_I2C_Reset(I2C_HandleTypeDef *hi2c);
void HAL_I2C_Enable(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AnalogFilterInit(I2C_HandleTypeDef *hi2c, HAL_I2C_AnalogFilterTypeDef AnalogFilter); void HAL_I2C_AnalogFilterInit(I2C_HandleTypeDef *hi2c, HAL_I2C_AnalogFilterTypeDef AnalogFilter);
void HAL_I2C_DigitalFilterInit(I2C_HandleTypeDef *hi2c, HAL_I2C_DigitalFilterTypeDef DigitalFilter); void HAL_I2C_DigitalFilterInit(I2C_HandleTypeDef *hi2c, HAL_I2C_DigitalFilterTypeDef DigitalFilter);
void HAL_I2C_SetClockSpeed(I2C_HandleTypeDef *hi2c); void HAL_I2C_SetClockSpeed(I2C_HandleTypeDef *hi2c);
@ -394,6 +391,7 @@ void HAL_I2C_SBCMode(I2C_HandleTypeDef *hi2c, HAL_I2C_SBCModeTypeDef SBCMode);
void HAL_I2C_SlaveInit(I2C_HandleTypeDef *hi2c); void HAL_I2C_SlaveInit(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterInit(I2C_HandleTypeDef *hi2c); void HAL_I2C_MasterInit(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c); HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_Deinit(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AutoEnd(I2C_HandleTypeDef *hi2c, HAL_I2C_AutoEndModeTypeDef AutoEnd); void HAL_I2C_AutoEnd(I2C_HandleTypeDef *hi2c, HAL_I2C_AutoEndModeTypeDef AutoEnd);
HAL_StatusTypeDef HAL_I2C_Master_WaitTXIS(I2C_HandleTypeDef *hi2c, uint32_t Timeout); HAL_StatusTypeDef HAL_I2C_Master_WaitTXIS(I2C_HandleTypeDef *hi2c, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_WaitRXNE(I2C_HandleTypeDef *hi2c, uint32_t Timeout); HAL_StatusTypeDef HAL_I2C_Master_WaitRXNE(I2C_HandleTypeDef *hi2c, uint32_t Timeout);
@ -427,6 +425,60 @@ HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pDa
HAL_StatusTypeDef HAL_I2C_Slave_Receive_NOSTRETCH_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t DataSize); HAL_StatusTypeDef HAL_I2C_Slave_Receive_NOSTRETCH_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t DataSize);
HAL_StatusTypeDef HAL_I2C_Slave_ReceiveSBC_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t DataSize); HAL_StatusTypeDef HAL_I2C_Slave_ReceiveSBC_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t DataSize);
static inline __attribute__((always_inline)) void HAL_I2C_Disable(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR1 &= ~I2C_CR1_PE_M;
}
static inline __attribute__((always_inline)) void HAL_I2C_Reset(I2C_HandleTypeDef *hi2c)
{
hi2c->ErrorCode = I2C_ERROR_NONE;
hi2c->Instance->CR1 &= ~I2C_CR1_PE_M;
hi2c->Instance->CR1 |= I2C_CR1_PE_M;
}
static inline __attribute__((always_inline)) void HAL_I2C_Enable(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR1 |= I2C_CR1_PE_M;
}
static inline __attribute__((always_inline)) void HAL_I2C_Reset_Interrupt_Flag(I2C_HandleTypeDef *hi2c, uint32_t mask)
{
hi2c->Instance->ICR |= mask;
}
static inline __attribute__((always_inline)) void HAL_I2C_Reset_TXDR_Content(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->ISR |= I2C_ISR_TXE_M;
}
static inline __attribute__((always_inline)) uint32_t HAL_I2C_Get_Interrupts_Status(I2C_HandleTypeDef *hi2c)
{
return hi2c->Instance->ISR;
}
static inline __attribute__((always_inline)) uint32_t HAL_I2C_Get_CR1_Content(I2C_HandleTypeDef *hi2c)
{
return hi2c->Instance->CR1;
}
static inline __attribute__((always_inline)) void HAL_I2C_Write_TXDR(I2C_HandleTypeDef *hi2c, uint8_t value)
{
hi2c->Instance->TXDR = value;
}
static inline __attribute__((always_inline)) uint8_t HAL_I2C_Get_RXDR(I2C_HandleTypeDef *hi2c)
{
return hi2c->Instance->RXDR;
}
static inline __attribute__((always_inline)) void HAL_I2C_Clear_Reload(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR2 &= ~I2C_CR2_RELOAD_M;
}
static inline __attribute__((always_inline)) void HAL_I2C_ADDR_IRQ(I2C_HandleTypeDef *hi2c) static inline __attribute__((always_inline)) void HAL_I2C_ADDR_IRQ(I2C_HandleTypeDef *hi2c)
{ {
if (hi2c->Instance->CR1 & I2C_CR1_SBC_M) if (hi2c->Instance->CR1 & I2C_CR1_SBC_M)

View File

@ -253,7 +253,8 @@ void HAL_SPI_CS_Disable(SPI_HandleTypeDef *hspi);
HAL_StatusTypeDef HAL_SPI_Exchange(SPI_HandleTypeDef *hspi, uint8_t TransmitBytes[], uint8_t ReceiveBytes[], uint32_t Size, uint32_t Timeout); HAL_StatusTypeDef HAL_SPI_Exchange(SPI_HandleTypeDef *hspi, uint8_t TransmitBytes[], uint8_t ReceiveBytes[], uint32_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_ExchangeThreshold(SPI_HandleTypeDef *hspi, uint8_t TransmitBytes[], uint8_t ReceiveBytes[], uint32_t DataSize, uint32_t Timeout); HAL_StatusTypeDef HAL_SPI_ExchangeThreshold(SPI_HandleTypeDef *hspi, uint8_t TransmitBytes[], uint8_t ReceiveBytes[], uint32_t DataSize, uint32_t Timeout);
HAL_StatusTypeDef HAL_SPI_Exchange_IT(SPI_HandleTypeDef *hspi, uint8_t TransmitBytes[], uint8_t ReceiveBytes[], uint32_t Size); HAL_StatusTypeDef HAL_SPI_Exchange_IT(SPI_HandleTypeDef *hspi, uint8_t TransmitBytes[], uint8_t ReceiveBytes[], uint32_t Size);
void HAL_SPI_Set_Clock_Divider(SPI_HandleTypeDef *hspi, uint8_t clockDiv);
void HAL_SPI_Set_Clock_Mode(SPI_HandleTypeDef *hspi, uint8_t CLKPhase, uint8_t CLKPolarity);
/** /**
* @brief Разрешить прерывания в соответствии с маской. * @brief Разрешить прерывания в соответствии с маской.

View File

@ -230,8 +230,6 @@ typedef struct __Timer16_HandleTypeDef
void HAL_TIMER16_MspInit(Timer16_HandleTypeDef* htimer16); void HAL_TIMER16_MspInit(Timer16_HandleTypeDef* htimer16);
void HAL_Timer16_Disable(Timer16_HandleTypeDef *htimer16);
void HAL_Timer16_Enable(Timer16_HandleTypeDef *htimer16);
void HAL_Timer16_SetActiveEdge(Timer16_HandleTypeDef *htimer16, uint8_t ActiveEdge); void HAL_Timer16_SetActiveEdge(Timer16_HandleTypeDef *htimer16, uint8_t ActiveEdge);
void HAL_Timer16_SetSourceClock(Timer16_HandleTypeDef *htimer16, uint8_t SourceClock); void HAL_Timer16_SetSourceClock(Timer16_HandleTypeDef *htimer16, uint8_t SourceClock);
void HAL_Timer16_SetCountMode(Timer16_HandleTypeDef *htimer16, uint8_t CountMode); void HAL_Timer16_SetCountMode(Timer16_HandleTypeDef *htimer16, uint8_t CountMode);
@ -278,6 +276,26 @@ void HAL_Timer16_SetInterruptARRM(Timer16_HandleTypeDef *htimer16);
void HAL_Timer16_SetInterruptCMPM(Timer16_HandleTypeDef *htimer16); void HAL_Timer16_SetInterruptCMPM(Timer16_HandleTypeDef *htimer16);
void HAL_Timer16_InterruptInit(Timer16_HandleTypeDef *htimer16); void HAL_Timer16_InterruptInit(Timer16_HandleTypeDef *htimer16);
/**
* @brief Выключить таймер.
* Может использоваться для отключения таймера или при записи в регистр CFGR.
*
* @param htimer16 Указатель на структуру с настройками Timer16.
*/
static inline void __attribute__((always_inline)) HAL_Timer16_Disable(Timer16_HandleTypeDef *htimer16)
{
htimer16->Instance->CR &= ~TIMER16_CR_ENABLE_M;
}
/**
* @brief Включить таймер
* @param htimer16 Указатель на структуру с настройками Timer16.
*/
static inline void __attribute__((always_inline)) HAL_Timer16_Enable(Timer16_HandleTypeDef *htimer16)
{
htimer16->Instance->CR |= TIMER16_CR_ENABLE_M;
}
/** /**
* @brief Получить статус прерываний Timer16. * @brief Получить статус прерываний Timer16.
* Функция возвращает статус прерываний в соответствии с маской разрешенный прерываний. * Функция возвращает статус прерываний в соответствии с маской разрешенный прерываний.
@ -291,6 +309,16 @@ static inline __attribute__((always_inline)) uint32_t HAL_Timer16_GetInterruptSt
return interrupt_status; return interrupt_status;
} }
/**
* @brief Получить статус прерывания по соответствию автозагрузке ARRM
* @param htimer16 Указатель на структуру с настройками Timer16
* @return Статус прерывания ARRM - true, если прерывание сработало
*/
static inline __attribute__((always_inline)) bool HAL_Timer16_GetInterruptStatus_ARRM(Timer16_HandleTypeDef *htimer16)
{
return (bool)((htimer16->Instance->ISR & htimer16->Instance->IER) & TIMER16_ISR_ARR_MATCH_M);
}
/** /**
* @brief Очистить флаг прерывания. * @brief Очистить флаг прерывания.
* @param htimer16 Указатель на структуру с настройками Timer16. * @param htimer16 Указатель на структуру с настройками Timer16.

View File

@ -226,6 +226,7 @@ static inline __attribute__((always_inline)) HAL_StatusTypeDef HAL_Timer32_WaitF
void HAL_TIMER32_MspInit(TIMER32_HandleTypeDef* htimer32); void HAL_TIMER32_MspInit(TIMER32_HandleTypeDef* htimer32);
void HAL_TIMER32_Channel_MspInit(TIMER32_CHANNEL_HandleTypeDef* timerChannel); void HAL_TIMER32_Channel_MspInit(TIMER32_CHANNEL_HandleTypeDef* timerChannel);
HAL_StatusTypeDef HAL_Timer32_Init(TIMER32_HandleTypeDef *timer); HAL_StatusTypeDef HAL_Timer32_Init(TIMER32_HandleTypeDef *timer);
HAL_StatusTypeDef HAL_Timer32_Deinit(TIMER32_HandleTypeDef *timer);
void HAL_Timer32_State_Set(TIMER32_HandleTypeDef *timer, HAL_TIMER32_StateTypeDef state); void HAL_Timer32_State_Set(TIMER32_HandleTypeDef *timer, HAL_TIMER32_StateTypeDef state);
void HAL_Timer32_Top_Set(TIMER32_HandleTypeDef *timer, uint32_t top); void HAL_Timer32_Top_Set(TIMER32_HandleTypeDef *timer, uint32_t top);
void HAL_Timer32_Prescaler_Set(TIMER32_HandleTypeDef *timer, uint32_t prescaler); void HAL_Timer32_Prescaler_Set(TIMER32_HandleTypeDef *timer, uint32_t prescaler);

View File

@ -93,58 +93,6 @@ HAL_StatusTypeDef HAL_GPIO_PinConfig(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin,
return HAL_GPIO_Init(GPIO_x, &GPIO_InitStruct); return HAL_GPIO_Init(GPIO_x, &GPIO_InitStruct);
} }
/**
* @brief Считать текущее состояние выводов порта GPIO_x.
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска выводов порта GPIO_x, с которых считывание значение.
* @return @ref GPIO_PIN_HIGH если с одного или больше выводов, указанных в pin, считалась 1. Иначе @ref GPIO_PIN_LOW.
*/
GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin)
{
GPIO_PinState bitStatus;
if ((GPIO_x->SET & pin) != (uint32_t)GPIO_PIN_LOW)
{
bitStatus = GPIO_PIN_HIGH;
}
else
{
bitStatus = GPIO_PIN_LOW;
}
return bitStatus;
}
/**
* @brief Задать логический уровень выходного сигнала для указанных выводов порта GPIO_x.
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска выводов порта GPIO_x, к которым применяются указанные настройки.
* @param pinState значение состояние вывода, в которое будут установлены указанные выводы.
* Этот параметр должен быть одним из значений:
* - @ref GPIO_PIN_LOW низкий выходной уровень
* - @ref GPIO_PIN_HIGH высокий выходной уровень
*/
void HAL_GPIO_WritePin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin, GPIO_PinState pinState)
{
if (pinState == GPIO_PIN_LOW)
{
GPIO_x->CLEAR = pin;
}
else
{
GPIO_x->SET = pin;
}
}
/**
* @brief Переключить логический уровень выходного сигнала для указанных выводов порта GPIO_x.
* @param GPIO_x порт GPIO_x, где x может быть (0, 1, 2).
* @param pin маска выводов порта GPIO_x, к которым применяются указанные настройки.
*/
void HAL_GPIO_TogglePin(GPIO_TypeDef *GPIO_x, HAL_PinsTypeDef pin)
{
GPIO_x->OUTPUT_ ^= pin;
}
/** /**
* @brief Функция инициализации линии прерывания. * @brief Функция инициализации линии прерывания.
* \param mux настройка мультиплексора линии прерывания. * \param mux настройка мультиплексора линии прерывания.
@ -222,39 +170,3 @@ HAL_StatusTypeDef HAL_GPIO_DeInitInterruptLine(HAL_GPIO_Line irqLine)
return HAL_OK; return HAL_OK;
} }
/**
* @brief Получить состояние линии прерывания.
* @param irqLine номер линии прерывания.
* @return Возвращает 1 если сработало прерывание данной линии, иначе 0.
*/
uint32_t HAL_GPIO_LineInterruptState(HAL_GPIO_Line irqLine)
{
int irq_line_num = irqLine >> GPIO_IRQ_LINE_S;
return (GPIO_IRQ->INTERRUPT & (1 << (irq_line_num))) != 0;
}
/**
* @brief Функция чтения логического уровня вывода, подключенного к линии прерывания.
* @param irqLine номер линии прерывания.
* @return Логический уровень вывода.
*/
GPIO_PinState HAL_GPIO_LinePinState(HAL_GPIO_Line irqLine)
{
int irq_line_num = irqLine >> GPIO_IRQ_LINE_S;
return (GPIO_PinState)((GPIO_IRQ->STATE & (1 << (irq_line_num))) >> irq_line_num);
}
/**
* @brief Функция сброса регистра состояния прерываний.
* @note Когда срабатывает прерывание на одной из линии, в регистре INTERRUPT
* выставляется 1 в разряде, соответствующем линии прерывания.
* После обработки прерывания необходимо сбросить данный регистр
* в обработчике прерывания trap_handler().
* Если после обработки прерывания регистр не был сброшен,
* обработчик будет вызван снова, программа будет бесконечно вызывать обработчик.
*/
void HAL_GPIO_ClearInterrupts()
{
GPIO_IRQ->CLEAR = 0b11111111;
}

View File

@ -26,24 +26,6 @@ __attribute__((weak)) void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
} }
void HAL_I2C_Disable(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR1 &= ~I2C_CR1_PE_M;
}
void HAL_I2C_Reset(I2C_HandleTypeDef *hi2c)
{
hi2c->ErrorCode = I2C_ERROR_NONE;
hi2c->Instance->CR1 &= ~I2C_CR1_PE_M;
hi2c->Instance->CR1 |= I2C_CR1_PE_M;
}
void HAL_I2C_Enable(I2C_HandleTypeDef *hi2c)
{
hi2c->Instance->CR1 |= I2C_CR1_PE_M;
}
void HAL_I2C_AnalogFilterInit(I2C_HandleTypeDef *hi2c, HAL_I2C_AnalogFilterTypeDef AnalogFilter) void HAL_I2C_AnalogFilterInit(I2C_HandleTypeDef *hi2c, HAL_I2C_AnalogFilterTypeDef AnalogFilter)
{ {
hi2c->Init.AnalogFilter = AnalogFilter; hi2c->Init.AnalogFilter = AnalogFilter;
@ -244,6 +226,24 @@ HAL_StatusTypeDef HAL_I2C_Init(I2C_HandleTypeDef *hi2c)
return HAL_OK; return HAL_OK;
} }
HAL_StatusTypeDef HAL_I2C_Deinit(I2C_HandleTypeDef *hi2c)
{
HAL_I2C_Disable(hi2c);
if (hi2c->Instance == I2C_0)
{
__HAL_PCC_I2C_0_CLK_DISABLE();
HAL_GPIO_PinConfig(GPIO_0, GPIO_PIN_9 | GPIO_PIN_10, HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
}
else if(hi2c->Instance == I2C_1)
{
__HAL_PCC_I2C_1_CLK_DISABLE();
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_12 | GPIO_PIN_13, HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
}
return HAL_OK;
}
void HAL_I2C_AutoEnd(I2C_HandleTypeDef *hi2c, HAL_I2C_AutoEndModeTypeDef AutoEnd) void HAL_I2C_AutoEnd(I2C_HandleTypeDef *hi2c, HAL_I2C_AutoEndModeTypeDef AutoEnd)
{ {
hi2c->Instance->CR2 &= ~I2C_CR2_AUTOEND_M; hi2c->Instance->CR2 &= ~I2C_CR2_AUTOEND_M;

View File

@ -282,6 +282,49 @@ HAL_StatusTypeDef HAL_SPI_Init(SPI_HandleTypeDef *hspi)
return error_code; return error_code;
} }
/**
* @brief Установить новый делитель частоты
*
* @param hspi указатель на структуру SPI_HandleTypeDef, которая содержит
* информацию о конфигурации для модуля SPI.
* @param clockDiv делитель частоты в пределах от SPI_BAUDRATE_DIV4 до SPI_BAUDRATE_DIV256
*/
void HAL_SPI_Set_Clock_Divider(SPI_HandleTypeDef *hspi, uint8_t clockDiv)
{
uint32_t config = hspi->Instance->CONFIG;
HAL_SPI_Disable(hspi);
hspi->Init.BaudRateDiv = clockDiv;
config &= ~(0b111 << SPI_CONFIG_BAUD_RATE_DIV_S); // очистить
config |= (hspi->Init.BaudRateDiv << SPI_CONFIG_BAUD_RATE_DIV_S); // установить новое
hspi->Instance->CONFIG = config; // сохранить конфигурацию
HAL_SPI_Enable(hspi);
}
/**
* @brief Установить новый режим работы
*
* @param hspi указатель на структуру SPI_HandleTypeDef, которая содержит
* информацию о конфигурации для модуля SPI.
* @param CLKPhase фаза тактирующего сигнала:
* 1 - тактовая частота SPI неактивна вне слова,
* 0 - тактовая частота SPI активна вне слова
* @param CLKPolarity полярность тактирующего сигнала
* 1 - тактовый сигнал удерживается на высоком уровне,
* 0 - тактовый сигнал удерживается на низком уровне
*/
void HAL_SPI_Set_Clock_Mode(SPI_HandleTypeDef *hspi, uint8_t CLKPhase, uint8_t CLKPolarity)
{
uint32_t config = hspi->Instance->CONFIG;
HAL_SPI_Disable(hspi);
hspi->Init.CLKPhase = CLKPhase;
hspi->Init.CLKPolarity = CLKPolarity;
config &= ~((1 << SPI_CONFIG_CLK_PH_S) | (1 << SPI_CONFIG_CLK_POL_S)); // очистить
config |= ((hspi->Init.CLKPhase << SPI_CONFIG_CLK_PH_S) |
(hspi->Init.CLKPolarity << SPI_CONFIG_CLK_POL_S)); // установить новые значения
hspi->Instance->CONFIG = config; // сохранить конфигурацию
HAL_SPI_Enable(hspi);
}
/** /**
* @brief Очистить буфер TX_FIFO. * @brief Очистить буфер TX_FIFO.
* *

View File

@ -99,26 +99,6 @@ __attribute__((weak)) void HAL_TIMER16_MspInit(Timer16_HandleTypeDef* htimer16)
} }
} }
/**
* @brief Выключить таймер.
* Может использоваться для отключения таймера или при записи в регистр CFGR.
*
* @param htimer16 Указатель на структуру с настройками Timer16.
*/
void HAL_Timer16_Disable(Timer16_HandleTypeDef *htimer16)
{
htimer16->Instance->CR &= ~TIMER16_CR_ENABLE_M;
}
/**
* @brief Включить таймер
* @param htimer16 Указатель на структуру с настройками Timer16.
*/
void HAL_Timer16_Enable(Timer16_HandleTypeDef *htimer16)
{
htimer16->Instance->CR |= TIMER16_CR_ENABLE_M;
}
/** /**
* @brief Установить активный фронт для подсчёта или задать подрежим энкодера. * @brief Установить активный фронт для подсчёта или задать подрежим энкодера.
* Используется при тактировании Timer16 от внешнего источника тактового сигнала на выводе Input1. * Используется при тактировании Timer16 от внешнего источника тактового сигнала на выводе Input1.

View File

@ -78,6 +78,41 @@ HAL_StatusTypeDef HAL_Timer32_Init(TIMER32_HandleTypeDef *timer)
return HAL_OK; return HAL_OK;
} }
HAL_StatusTypeDef HAL_Timer32_Deinit(TIMER32_HandleTypeDef *timer)
{
if ((timer->Instance != TIMER32_0) && (timer->Instance != TIMER32_1) && (timer->Instance != TIMER32_2))
{
return HAL_ERROR;
}
if (timer->Instance == TIMER32_0)
{
__HAL_PCC_TIMER32_0_CLK_DISABLE();
}
if (timer->Instance == TIMER32_1)
{
__HAL_PCC_TIMER32_1_CLK_DISABLE();
if (timer->Clock.Source == TIMER32_SOURCE_TX_PAD)
HAL_GPIO_PinConfig(GPIO_0, GPIO_PIN_4, HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
}
if (timer->Instance == TIMER32_2)
{
__HAL_PCC_TIMER32_2_CLK_DISABLE();
if (timer->Clock.Source == TIMER32_SOURCE_TX_PAD)
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_4, HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
}
HAL_Timer32_InterruptMask_Clear(timer, 0xFFFFFFFF);
HAL_Timer32_Prescaler_Set(timer, 0);
HAL_Timer32_InterruptFlags_ClearMask(timer, 0xFFFFFFFF);
HAL_Timer32_InterruptFlags_Clear(timer);
return HAL_OK;
}
void HAL_Timer32_State_Set(TIMER32_HandleTypeDef *timer, HAL_TIMER32_StateTypeDef state) void HAL_Timer32_State_Set(TIMER32_HandleTypeDef *timer, HAL_TIMER32_StateTypeDef state)
{ {
timer->State = state; timer->State = state;
@ -199,7 +234,7 @@ HAL_StatusTypeDef HAL_Timer32_Channel_Init(TIMER32_CHANNEL_HandleTypeDef *timerC
return HAL_ERROR; return HAL_ERROR;
} }
HAL_TIMER32_Channel_MspInit(timerChannel); // HAL_TIMER32_Channel_MspInit(timerChannel); // здесь инициализируются сразу все каналы выбранного таймера, а нам такого не надо
timerChannel->Instance = (TIMER32_CHANNEL_TypeDef *)&(timerChannel->TimerInstance->CHANNELS[timerChannel->ChannelIndex]); timerChannel->Instance = (TIMER32_CHANNEL_TypeDef *)&(timerChannel->TimerInstance->CHANNELS[timerChannel->ChannelIndex]);
@ -220,6 +255,8 @@ HAL_StatusTypeDef HAL_Timer32_Channel_DeInit(TIMER32_CHANNEL_HandleTypeDef *time
return HAL_ERROR; return HAL_ERROR;
} }
timerChannel->Instance = (TIMER32_CHANNEL_TypeDef *)&(timerChannel->TimerInstance->CHANNELS[timerChannel->ChannelIndex]);
HAL_Timer32_Channel_Disable(timerChannel); HAL_Timer32_Channel_Disable(timerChannel);
HAL_Timer32_Channel_CaptureEdge_Set(timerChannel, 0); HAL_Timer32_Channel_CaptureEdge_Set(timerChannel, 0);
HAL_Timer32_Channel_ICR_Clear(timerChannel); HAL_Timer32_Channel_ICR_Clear(timerChannel);

View File

@ -68,25 +68,8 @@ static TIMER32_HandleTypeDef htimer32;
static TIMER32_CHANNEL_HandleTypeDef htimer32_channel; static TIMER32_CHANNEL_HandleTypeDef htimer32_channel;
static uint32_t WriteValMax = WRITE_VAL_MAX_DEFAULT; static uint32_t WriteValMax = WRITE_VAL_MAX_DEFAULT;
static uint32_t pwmTopVal = PWM_TOP_VAL_DEFAULT; static uint32_t pwmTopVal = PWM_TOP_VAL_DEFAULT;
static bool pwmIsInited = false; static uint8_t pwmIsInited = 0;
HAL_StatusTypeDef Timer32_Channel_Init(TIMER32_CHANNEL_HandleTypeDef *timerChannel)
{
if (timerChannel->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: It is recommended to enable the timer in the following order:
@ -120,15 +103,15 @@ void analogWrite(uint32_t PinNumber, uint32_t writeVal)
htimer32_channel.PWM_Invert = TIMER32_CHANNEL_NON_INVERTED_PWM; htimer32_channel.PWM_Invert = TIMER32_CHANNEL_NON_INVERTED_PWM;
htimer32_channel.Mode = TIMER32_CHANNEL_MODE_PWM; htimer32_channel.Mode = TIMER32_CHANNEL_MODE_PWM;
htimer32_channel.CaptureEdge = TIMER32_CHANNEL_CAPTUREEDGE_RISING; 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.OCR = (uint32_t) (((uint64_t)pwmTopVal * writeVal) / WriteValMax);
htimer32_channel.Noise = TIMER32_CHANNEL_FILTER_OFF; htimer32_channel.Noise = TIMER32_CHANNEL_FILTER_OFF;
Timer32_Channel_Init(&htimer32_channel); HAL_Timer32_Channel_Init(&htimer32_channel);
// start timer with initialized channel // start timer with initialized channel
HAL_Timer32_Channel_Enable(&htimer32_channel); HAL_Timer32_Channel_Enable(&htimer32_channel);
HAL_Timer32_Value_Clear(&htimer32); HAL_Timer32_Value_Clear(&htimer32);
HAL_Timer32_Start(&htimer32); HAL_Timer32_Start(&htimer32);
pwmIsInited = true; // if at least one channel is working, say that the module is initialized pwmIsInited++; // increase inited channels qty
} }
else if(PinNumber == 10) // pin d10 has pwm, but you cannot use it while spi is running 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"); ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running");
@ -165,21 +148,26 @@ It is recommended to turn off the timer in the following order:
*/ */
void analogWriteStop(uint32_t PinNumber) void analogWriteStop(uint32_t PinNumber)
{ {
if (pwmIsInited) if ((pwmIsInited > 0) && (digitalPinPwmIsOn(PinNumber)))
{ {
// load the timer address and channel number corresponding to the specified pin // load the timer address and channel number corresponding to the specified pin
htimer32.Instance = pwmPinToTimer(PinNumber); htimer32.Instance = pwmPinToTimer(PinNumber);
htimer32_channel.TimerInstance = htimer32.Instance; htimer32_channel.TimerInstance = htimer32.Instance;
htimer32_channel.ChannelIndex = pwmPinToTimerChannel(PinNumber); htimer32_channel.ChannelIndex = pwmPinToTimerChannel(PinNumber);
// in the initChannel function they do it inside, but in deinit they don't. We do it outside // deinit channel
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_Channel_DeInit(&htimer32_channel);
HAL_Timer32_Stop(&htimer32); pwmIsInited--; // decrease inited channels qty
pwmIsInited = false;
// stop timer if no inited channels left
if (pwmIsInited == 0)
{
HAL_Timer32_Stop(&htimer32);
HAL_Timer32_Deinit(&htimer32);
}
// config pin as input when timer channel off
HAL_GPIO_PinConfig(digitalPinToPort(PinNumber), digitalPinToBitMask(PinNumber),
HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
} }
} }

View File

@ -50,53 +50,18 @@ void SPISettings::spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, ui
} }
// ------------------------------------------------------------------ // // ------------------------------------------------------------------ //
// pins shift in gpio register
#define PIN_1_3_GPIO_S 3
#define PIN_1_4_GPIO_S 4
SPIClass SPI; SPIClass SPI;
bool SPIClass::spiInUse = false; bool SPIClass::spiInUse = false;
uint8_t SPIClass::interruptMode = 0; uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0; uint8_t SPIClass::interruptMask = 0;
#define PAD_GET_PIN_CONFIG(port, pin) (((PAD_CONFIG->port) & (0b11<<(2*pin))) >> (2*pin))
void SPIClass::begin() void SPIClass::begin()
{ {
// there is a seller on pin 1.6 which replace D10 from spi NSS pin 1.3 to pin 1.4, spi_onBegin();
// because spi needs pin 1.3 for correct work
// replace config from 1.3 to 1.4
uint8_t config = ((PAD_CONFIG->PORT_1_CFG) & (0b11<<(2*PIN_1_3_GPIO_S))) >> (2*PIN_1_3_GPIO_S);
if (config == 0) // common gpio
{
// pin direction
uint8_t direction = ((GPIO_1->DIRECTION_IN) & (1<<PIN_1_3_GPIO_S)) >> PIN_1_3_GPIO_S;
if (direction == 1) // input
GPIO_1->DIRECTION_IN |= (1<<PIN_1_4_GPIO_S);
else // output
GPIO_1->DIRECTION_OUT |= (1<<PIN_1_4_GPIO_S);
// pull up/down
uint8_t pupd_1_3 = ((PAD_CONFIG ->PORT_1_PUPD) & (0b11<<(2*PIN_1_3_GPIO_S))) >> (2*PIN_1_3_GPIO_S);
PAD_CONFIG ->PORT_1_PUPD &= (~(0b11<<(2*PIN_1_4_GPIO_S))); // clear
PAD_CONFIG ->PORT_1_PUPD |= ((pupd_1_3&0b11)<<(2*PIN_1_4_GPIO_S)); // set new
//current state
uint8_t state1_3 = ((GPIO_1->OUTPUT_) & (1<<PIN_1_3_GPIO_S)) >> PIN_1_3_GPIO_S;
GPIO_1->OUTPUT_ &= (~(0b1<<PIN_1_4_GPIO_S)); // clear
GPIO_1->OUTPUT_ |= ((state1_3&0b1)<<PIN_1_4_GPIO_S); // set new
}
else if(config == 2) // timer for pwm
{
// if D10 (spi NSS pin) was used as pwm, we need to stop timer,
// because 1.4 don't support timer
analogWriteStop(10);
ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running");
}
// switch seller to pin 1.4
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_6, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_HIGH);
blockSpiPin();
spiInUse = true; spiInUse = true;
} }
@ -113,31 +78,9 @@ void SPIClass::end()
{ {
HAL_GPIO_PinConfig(GPIO_1, (HAL_PinsTypeDef)(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2), HAL_GPIO_PinConfig(GPIO_1, (HAL_PinsTypeDef)(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2),
HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
} }
// return D10 with common gpio config to pin 1.3 spi_onEnd();
PAD_CONFIG->PORT_1_CFG &= (~(0b11<<(2*PIN_1_3_GPIO_S))); // set config to 0 - common gpio mode
// pin direction
uint8_t direction = ((GPIO_1->DIRECTION_IN) & (1<<PIN_1_4_GPIO_S)) >> PIN_1_4_GPIO_S;
if (direction == 1) // input
GPIO_1->DIRECTION_IN |= (1<<PIN_1_3_GPIO_S);
else // output
GPIO_1->DIRECTION_OUT |= (1<<PIN_1_3_GPIO_S);
// pull up/down
uint8_t pupd_1_4 = ((PAD_CONFIG ->PORT_1_PUPD) & (0b11<<(2*PIN_1_4_GPIO_S))) >> (2*PIN_1_4_GPIO_S);
PAD_CONFIG ->PORT_1_PUPD &= (~(0b11<<(2*PIN_1_3_GPIO_S))); // clear
PAD_CONFIG ->PORT_1_PUPD |= ((pupd_1_4&0b11)<<(2*PIN_1_3_GPIO_S)); // set new
// current state
uint8_t state1_4 = ((GPIO_1->OUTPUT_) & (1<<PIN_1_4_GPIO_S)) >> PIN_1_4_GPIO_S;
GPIO_1->OUTPUT_ &= (~(0b1<<PIN_1_3_GPIO_S)); // clear
GPIO_1->OUTPUT_ |= ((state1_4&0b1)<<PIN_1_3_GPIO_S); // set new
// switch seller back to pin 1.3
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW);
unblockSpiPin();
spiInUse = false; spiInUse = false;
isInited = false; isInited = false;
@ -304,30 +247,22 @@ void SPIClass::setBitOrder(uint8_t bitOrder)
void SPIClass::setDataMode(uint8_t dataMode) void SPIClass::setDataMode(uint8_t dataMode)
{ {
uint32_t config = hspi.Instance->CONFIG; // ClkPhase ClkPolarity
HAL_SPI_Disable(&hspi); HAL_SPI_Set_Clock_Mode(&hspi, (dataMode&0b00000001), (dataMode&0b00000010)>>1);
hspi.Init.CLKPhase = dataMode & 0b00000001;
hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1;
config &= ~((1 << SPI_CONFIG_CLK_PH_S) | (1 << SPI_CONFIG_CLK_POL_S)); // clear
config |= ((hspi.Init.CLKPhase << SPI_CONFIG_CLK_PH_S) |
(hspi.Init.CLKPolarity << SPI_CONFIG_CLK_POL_S)); // set new
hspi.Instance->CONFIG = config;
HAL_SPI_Enable(&hspi);
} }
void SPIClass::setClockDivider(uint8_t clockDiv) void SPIClass::setClockDivider(uint8_t clockDiv)
{ {
// if divider is in valid range // if divider is valid
if ((clockDiv >= SPI_CLOCK_DIV4) && (clockDiv <= SPI_CLOCK_DIV256)) if ((clockDiv == SPI_CLOCK_DIV4) || (clockDiv == SPI_CLOCK_DIV8) ||
(clockDiv == SPI_CLOCK_DIV16) || (clockDiv == SPI_CLOCK_DIV32) ||
(clockDiv == SPI_CLOCK_DIV64) || (clockDiv == SPI_CLOCK_DIV128) ||
(clockDiv == SPI_CLOCK_DIV256))
{ {
uint32_t config = hspi.Instance->CONFIG; HAL_SPI_Set_Clock_Divider(&hspi, clockDiv);
HAL_SPI_Disable(&hspi);
hspi.Init.BaudRateDiv = clockDiv;
config &= ~(0b111 << SPI_CONFIG_BAUD_RATE_DIV_S); // clear
config |= (hspi.Init.BaudRateDiv << SPI_CONFIG_BAUD_RATE_DIV_S); // set new
hspi.Instance->CONFIG = config;
HAL_SPI_Enable(&hspi);
} }
else
ErrorMsgHandler("SPI.setClockDivider(): Invalid clock devider");
} }
static uint8_t reverse_bits(uint8_t byte) static uint8_t reverse_bits(uint8_t byte)

View File

@ -88,36 +88,22 @@ void twi_deinit(void)
{ {
uint32_t EPICmask; uint32_t EPICmask;
HAL_I2C_Disable(&hi2c);
// disable clock
#if I2C_NUM == 0 #if I2C_NUM == 0
hi2c.Instance = I2C_0; hi2c.Instance = I2C_0;
EPICmask = HAL_EPIC_I2C_0_MASK; EPICmask = HAL_EPIC_I2C_0_MASK;
__HAL_PCC_I2C_0_CLK_DISABLE();
#elif I2C_NUM == 1 #elif I2C_NUM == 1
hi2c.Instance = I2C_1; hi2c.Instance = I2C_1;
EPICmask = HAL_EPIC_I2C_1_MASK; EPICmask = HAL_EPIC_I2C_1_MASK;
__HAL_PCC_I2C_1_CLK_DISABLE();
#else #else
#error "Unsupported I2C_NUM value in pins_arduino.h" #error "Unsupported I2C_NUM value in pins_arduino.h"
#endif #endif
HAL_I2C_Deinit(&hi2c);
// for slave mode disable interrupts from i2c // for slave mode disable interrupts from i2c
if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE) if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE)
HAL_EPIC_MaskLevelClear(EPICmask); HAL_EPIC_MaskLevelClear(EPICmask);
// reconfigure pins to z state
GPIO_InitTypeDef GPIO_InitStruct;
memset(&GPIO_InitStruct, 0, sizeof(GPIO_InitStruct));
// SDA
GPIO_InitStruct.Pin = (HAL_PinsTypeDef)digitalPinToBitMask(PIN_WIRE_SDA);
GPIO_InitStruct.Mode = HAL_GPIO_MODE_GPIO_INPUT;
GPIO_InitStruct.Pull = HAL_GPIO_PULL_NONE;
HAL_GPIO_Init(digitalPinToPort(PIN_WIRE_SDA), &GPIO_InitStruct);
// SCL
GPIO_InitStruct.Pin = (HAL_PinsTypeDef)digitalPinToBitMask(PIN_WIRE_SCL);
HAL_GPIO_Init(digitalPinToPort(PIN_WIRE_SCL), &GPIO_InitStruct);
twiIsOn = false; twiIsOn = false;
} }
@ -252,7 +238,7 @@ uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_
// parse errors // parse errors
// check separately, because in hal libraries not all functions look at this // check separately, because in hal libraries not all functions look at this
if (hi2c.Instance->ISR & I2C_ISR_NACKF_M) if (HAL_I2C_Get_Interrupts_Status(&hi2c) & I2C_ISR_NACKF_M)
hi2c.ErrorCode = I2C_ERROR_NACK; hi2c.ErrorCode = I2C_ERROR_NACK;
if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_TIMEOUT) ret = I2C_TIMEOUT; // timeout if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_TIMEOUT) ret = I2C_TIMEOUT; // timeout
else if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_NACK) ret = I2C_NACK_DATA; // didn't receive ACK else if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_NACK) ret = I2C_NACK_DATA; // didn't receive ACK
@ -275,39 +261,35 @@ i2c_status_e twi_slaveWrite(uint8_t *txData, uint8_t bytesNum)
if ((hi2c.ErrorCode != I2C_ERROR_NONE)) if ((hi2c.ErrorCode != I2C_ERROR_NONE))
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(&hi2c);
// отправка данных // send data
HAL_StatusTypeDef error_code = HAL_OK; HAL_StatusTypeDef error_code = HAL_OK;
HAL_I2C_Clear_Reload(&hi2c);
hi2c.Instance->CR2 &= ~I2C_CR2_RELOAD_M; if (!(HAL_I2C_Get_CR1_Content(&hi2c) & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0
HAL_I2C_Reset_TXDR_Content(&hi2c);
HAL_I2C_Write_TXDR(&hi2c, txData[0]); // first recording is made in advance
if (!(hi2c.Instance->CR1 & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0 // write byte
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents
hi2c.Instance->TXDR = txData[0]; // The first recording is made in advance
// Запись байта
for (uint32_t tx_count = 1; tx_count < bytesNum; tx_count++) for (uint32_t tx_count = 1; tx_count < bytesNum; tx_count++)
{ {
if ((error_code = HAL_I2C_Slave_WaitTXIS(&hi2c, TIMEOUT_TICKS)) != HAL_OK) if ((error_code = HAL_I2C_Slave_WaitTXIS(&hi2c, TIMEOUT_TICKS)) != HAL_OK)
{ {
// неудачная запись // failed to write
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents HAL_I2C_Reset_TXDR_Content(&hi2c);
hi2c.Instance->ICR |= I2C_ICR_STOPCF_M; // Clear the STOP detection flag on the bus HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(&hi2c);
return I2C_TIMEOUT; return I2C_TIMEOUT;
} }
hi2c.Instance->TXDR = txData[tx_count]; HAL_I2C_Write_TXDR(&hi2c, txData[tx_count]);
} }
if ((error_code = HAL_I2C_WaitBusy(&hi2c, TIMEOUT_TICKS)) != HAL_OK) if ((error_code = HAL_I2C_WaitBusy(&hi2c, TIMEOUT_TICKS)) != HAL_OK)
{ {
// неудачное завершение транзакции // failed to complete transaction
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(&hi2c);
return I2C_TIMEOUT; return I2C_TIMEOUT;
} }
HAL_I2C_Reset_TXDR_Content(&hi2c);
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus
hi2c.Instance->ICR |= I2C_ICR_STOPCF_M; // Clear the STOP detection flag on the bus
return I2C_OK; return I2C_OK;
} }
@ -343,25 +325,24 @@ void twi_attachSlaveTxEvent( void (*function)(void) )
*/ */
void twi_interruptHandler(void) void twi_interruptHandler(void)
{ {
uint32_t int_mask = hi2c.Instance->CR1 & I2C_INTMASK; // interrupts allowed uint32_t int_mask = HAL_I2C_Get_CR1_Content(&hi2c) & I2C_INTMASK; // interrupts allowed
uint32_t interrupt_status = hi2c.Instance->ISR; // current flags uint32_t interrupt_status = HAL_I2C_Get_Interrupts_Status(&hi2c); // current flags
// master calls by address, device in slave mode // master calls by address, device in slave mode
if ((interrupt_status & I2C_ISR_ADDR_M) && (int_mask & I2C_CR1_ADDRIE_M)) if ((interrupt_status & I2C_ISR_ADDR_M) && (int_mask & I2C_CR1_ADDRIE_M))
{ {
// reset ADDR flag // reset ADDR flag
hi2c.Instance->ICR |= I2C_ICR_ADDRCF_M; HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_ADDRCF_M);
// look at the transmission direction and respond to the request // look at the transmission direction and respond to the request
if (interrupt_status & I2C_ISR_DIR_M) // master reads, slave sends if (interrupt_status & I2C_ISR_DIR_M) // master reads, slave sends
// отправляем данные twi_onSlaveTransmit(); // slave send data
twi_onSlaveTransmit();
else // master writes, slave reads else // master writes, slave reads
{ {
twi_rxBufferIndex = 0; // write from the beginning of the buffer twi_rxBufferIndex = 0; // write from the beginning of the buffer
hi2c.State = HAL_I2C_STATE_BUSY; hi2c.State = HAL_I2C_STATE_BUSY;
hi2c.Instance->CR2 &= ~I2C_CR2_RELOAD_M; HAL_I2C_Clear_Reload(&hi2c);
// wait for interrupts because of receiving a byte or a stop condition // wait for interrupts by receiving a byte or a stop condition
} }
} }
@ -369,15 +350,15 @@ void twi_interruptHandler(void)
if ((interrupt_status & I2C_ISR_RXNE_M) && (int_mask & I2C_CR1_RXIE_M)) if ((interrupt_status & I2C_ISR_RXNE_M) && (int_mask & I2C_CR1_RXIE_M))
{ {
// put new byte into buffer // put new byte into buffer
twi_rxBuffer[twi_rxBufferIndex++] = (uint8_t)hi2c.Instance->RXDR; twi_rxBuffer[twi_rxBufferIndex++] = HAL_I2C_Get_RXDR(&hi2c);
} }
// master sent a STOP to the bus // master sent a STOP to the bus
if ((interrupt_status & I2C_ISR_STOPF_M) && (int_mask & I2C_CR1_STOPIE_M)) if ((interrupt_status & I2C_ISR_STOPF_M) && (int_mask & I2C_CR1_STOPIE_M))
{ {
hi2c.State = HAL_I2C_STATE_END; hi2c.State = HAL_I2C_STATE_END;
hi2c.Instance->ISR |= I2C_ISR_TXE_M; // Reset TXDR contents HAL_I2C_Reset_TXDR_Content(&hi2c);
hi2c.Instance->ICR |= I2C_ICR_STOPCF_M; // Clear the STOP detection flag on the bus HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus
// pass the received data to callback function // pass the received data to callback function
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex);
} }

View File

@ -32,8 +32,6 @@ extern "C" {
#include "mik32_hal_gpio.h" #include "mik32_hal_gpio.h"
#include "mik32_hal_timer32.h" #include "mik32_hal_timer32.h"
extern bool spiNssPinIsBlocked;
// analog pins // analog pins
#define PIN_A0 (14) #define PIN_A0 (14)
#define PIN_A1 (15) #define PIN_A1 (15)
@ -78,6 +76,7 @@ uint32_t analogInputToChannelNumber(uint32_t PinNumber);
// PWM // PWM
bool digitalPinHasPWM(uint8_t p); bool digitalPinHasPWM(uint8_t p);
bool digitalPinPwmIsOn(uint8_t digitalPin); // use only if digitalPinHasPWM() == true
// determines which timer the pin belongs to // determines which timer the pin belongs to
TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber); TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber);
// determines which timer channel the pin belongs to // determines which timer channel the pin belongs to
@ -94,19 +93,13 @@ static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK; static const uint8_t SCK = PIN_SPI_SCK;
// config SEL_NSS1 to replace D10 to different controller pin, // config SEL_NSS1 to replace D10 to different controller pin,
// because pin 1.3 which is D10 by default is needed to spi // because pin 1.3 which is D10 by default is needed to spi
inline void blockSpiPin(void) void spi_onBegin(void);
{ void spi_onEnd(void);
spiNssPinIsBlocked = true;
}
inline void unblockSpiPin(void)
{
spiNssPinIsBlocked = false;
}
// I2C // I2C
#define PIN_WIRE_SDA (18) #define PIN_WIRE_SDA (18)
#define PIN_WIRE_SCL (19) #define PIN_WIRE_SCL (19)
#define I2C_NUM (1) // i2c number 0 or 1 #define I2C_NUM (1) // i2c number 1
static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SDA = PIN_WIRE_SDA;
static const uint8_t SCL = PIN_WIRE_SCL; static const uint8_t SCL = PIN_WIRE_SCL;
// available frequencies // available frequencies

View File

@ -13,6 +13,7 @@
#include "pins_arduino.h" #include "pins_arduino.h"
#include "mik32_hal_adc.h" #include "mik32_hal_adc.h"
#include "wiring_analog.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -106,6 +107,10 @@ volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x)
return &GPIO_x->STATE; return &GPIO_x->STATE;
} }
// return config of pin with pinShift(0...16) in portReg (config, pupd, ds for ports 0...2)
#define PIN_PAD_CONFIG(portReg, pinShift) ((PAD_CONFIG->portReg >> (pinShift<<1)) & 0b11)
// ---------------------- ADC ---------------------- // // ---------------------- ADC ---------------------- //
// determines the ADC channel number by the board pin number // determines the ADC channel number by the board pin number
uint32_t analogInputToChannelNumber(uint32_t PinNumber) uint32_t analogInputToChannelNumber(uint32_t PinNumber)
@ -141,6 +146,38 @@ uint32_t analogInputToChannelNumber(uint32_t PinNumber)
} }
// ---------------------- PWM ---------------------- // // ---------------------- PWM ---------------------- //
// use only if digitalPinHasPWM() == true
#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)) ? 1:0)
// use only if digitalPinHasPWM() == true
static inline uint8_t pwmPinToGpioPinShift(uint8_t digitalPin)
{
if (digitalPin == 3)
return 0;
else if ((digitalPin == 5) || (digitalPin == 11))
return 1;
else if (digitalPin == 6)
return 2;
else // pins 9 10
return 3;
}
// use only if digitalPinHasPWM() == true
// return true if digitalPin configured as pwm
bool digitalPinPwmIsOn(uint8_t digitalPin)
{
uint8_t config = 0;
uint8_t pinShift = pwmPinToGpioPinShift(digitalPin);
if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0)
config = PIN_PAD_CONFIG(PORT_0_CFG, pinShift);
else
config = PIN_PAD_CONFIG(PORT_1_CFG, pinShift);
if (config == 2)
return true;
else
return false;
}
bool digitalPinHasPWM(uint8_t p) bool digitalPinHasPWM(uint8_t p)
{ {
bool ret = false; bool ret = false;
@ -225,4 +262,52 @@ int8_t digitalPinToInterrupt(uint32_t digPinNumber)
return i; return i;
} }
return NOT_AN_INTERRUPT; return NOT_AN_INTERRUPT;
}
// ---------------------- SPI ---------------------- //
// pins shift in registers
#define PIN_3_SHIFT 3
#define PIN_4_SHIFT 4
#define PORT1_GET_PAD_PUPD(pinShift) ((PAD_CONFIG->PORT_1_PUPD >> (pinShift<<1)) & 0b11)
#define PORT1_GET_GPIO_STATE(pinShift) ((GPIO_1->OUTPUT_ >> pinShift) & 0b1)
void spi_onBegin(void)
{
// On Elbear Ace-Uno rev1.1.0 there is a seller on pin 1.6 which replace D10 from spi NSS pin 1.3 to pin 1.4,
// because spi needs pin 1.3 for correct work
// replace config from 1.3 to 1.4
uint8_t config = PIN_PAD_CONFIG(PORT_1_CFG, PIN_3_SHIFT);
if (config == 0) // common gpio
{
// get info from pin gpio1.3 and set config to gpio1.4
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_4, HAL_GPIO_GetPinDirection(GPIO_1, GPIO_PIN_3),
(HAL_GPIO_PullTypeDef)PORT1_GET_PAD_PUPD(PIN_3_SHIFT), HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_4, (GPIO_PinState)PORT1_GET_GPIO_STATE(PIN_3_SHIFT));
// pin D10 was switched to different gpio and can be used further
}
else if(config == 2) // timer for pwm
{
// if D10 (spi NSS pin) was used as pwm, we need to stop timer, because 1.4 don't support it
analogWriteStop(10);
ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running");
}
// switch seller to pin 1.4
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_6, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_HIGH);
spiNssPinIsBlocked = true; // block spi pin
}
void spi_onEnd(void)
{
// get info from pin gpio1.4 and set config to gpio1.3
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_3, HAL_GPIO_GetPinDirection(GPIO_1, GPIO_PIN_4),
(HAL_GPIO_PullTypeDef)PORT1_GET_PAD_PUPD(PIN_4_SHIFT), HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_3, (GPIO_PinState)PORT1_GET_GPIO_STATE(PIN_4_SHIFT));
// switch seller back to pin 1.3
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW);
spiNssPinIsBlocked = false; // unblock spi pin
} }