feat: initial
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					.DS_Store
 | 
				
			||||||
							
								
								
									
										90
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										90
									
								
								README.md
									
									
									
									
									
								
							@@ -1,3 +1,89 @@
 | 
				
			|||||||
# zh_avr_encoder
 | 
					# FreeRTOS based AVR library for rotary encoder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
FreeRTOS based AVR library for rotary encoder.
 | 
					## Features
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Support some encoders on one device.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Using
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In an existing project, run the following command to install the components:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```text
 | 
				
			||||||
 | 
					cd ../your_project/lib
 | 
				
			||||||
 | 
					git clone http://git.zh.com.ru/avr_libraries/zh_avr_free_rtos
 | 
				
			||||||
 | 
					git clone http://git.zh.com.ru/avr_libraries/zh_avr_common
 | 
				
			||||||
 | 
					git clone http://git.zh.com.ru/avr_libraries/zh_avr_encoder
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the application, add the component:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					#include "zh_avr_encoder.h"
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					One encoder on device:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					#include "avr/io.h"
 | 
				
			||||||
 | 
					#include "stdio.h"
 | 
				
			||||||
 | 
					#include "zh_avr_encoder.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BAUD_RATE 9600
 | 
				
			||||||
 | 
					#define BAUD_PRESCALE (F_CPU / 16 / BAUD_RATE - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usart(char byte, FILE *stream)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    while ((UCSR0A & (1 << UDRE0)) == 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    UDR0 = byte;
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					FILE uart = FDEV_SETUP_STREAM(usart, NULL, _FDEV_SETUP_WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					zh_avr_encoder_handle_t encoder_handle = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    UBRR0H = (BAUD_PRESCALE >> 8);
 | 
				
			||||||
 | 
					    UBRR0L = BAUD_PRESCALE;
 | 
				
			||||||
 | 
					    UCSR0B = (1 << RXEN0) | (1 << TXEN0);
 | 
				
			||||||
 | 
					    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
 | 
				
			||||||
 | 
					    stdout = &uart;
 | 
				
			||||||
 | 
					    zh_avr_encoder_init_config_t encoder_init_config = ZH_AVR_ENCODER_INIT_CONFIG_DEFAULT();
 | 
				
			||||||
 | 
					    encoder_init_config.gpio_port = AVR_PORTD;
 | 
				
			||||||
 | 
					    encoder_init_config.a_gpio_number = PORTD5;
 | 
				
			||||||
 | 
					    encoder_init_config.b_gpio_number = PORTD6;
 | 
				
			||||||
 | 
					    encoder_init_config.pullup = true;
 | 
				
			||||||
 | 
					    encoder_init_config.encoder_min_value = -10;
 | 
				
			||||||
 | 
					    encoder_init_config.encoder_max_value = 20;
 | 
				
			||||||
 | 
					    encoder_init_config.encoder_step = 1;
 | 
				
			||||||
 | 
					    encoder_init_config.encoder_number = 1;
 | 
				
			||||||
 | 
					    zh_avr_encoder_init(&encoder_init_config, &encoder_handle);
 | 
				
			||||||
 | 
					    double position = 0;
 | 
				
			||||||
 | 
					    zh_avr_encoder_get(&encoder_handle, &position);
 | 
				
			||||||
 | 
					    printf("Encoder position %d.\n", (int)position);
 | 
				
			||||||
 | 
					    zh_avr_encoder_set(&encoder_handle, 5);
 | 
				
			||||||
 | 
					    zh_avr_encoder_reset(&encoder_handle);
 | 
				
			||||||
 | 
					    vTaskStartScheduler();
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void zh_avr_encoder_event_handler(zh_avr_encoder_event_on_isr_t *event) // Do not delete!
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    printf("Encoder number %d position %d.\n", event->encoder_number, (int)event->encoder_position);
 | 
				
			||||||
 | 
					    printf("Interrupt Task Remaining Stack Size %d.\n", uxTaskGetStackHighWaterMark(NULL));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ISR(PCINT0_vect) // For AVR_PORTB.
 | 
				
			||||||
 | 
					// ISR(PCINT1_vect) // For AVR_PORTC.
 | 
				
			||||||
 | 
					ISR(PCINT2_vect) // For AVR_PORTD.
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (zh_avr_encoder_isr_handler(&encoder_handle) == pdTRUE)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        portYIELD();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										119
									
								
								include/zh_avr_encoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								include/zh_avr_encoder.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
				
			|||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "FreeRTOS.h"
 | 
				
			||||||
 | 
					#include "semphr.h"
 | 
				
			||||||
 | 
					#include "avr_err.h"
 | 
				
			||||||
 | 
					#include "avr_port.h"
 | 
				
			||||||
 | 
					#include "stdbool.h"
 | 
				
			||||||
 | 
					#include "avr/interrupt.h"
 | 
				
			||||||
 | 
					#include "avr/pgmspace.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ZH_AVR_ENCODER_INIT_CONFIG_DEFAULT()   \
 | 
				
			||||||
 | 
					    {                                          \
 | 
				
			||||||
 | 
					        .task_priority = configMAX_PRIORITIES, \
 | 
				
			||||||
 | 
					        .stack_size = 124,                     \
 | 
				
			||||||
 | 
					        .queue_size = 1,                       \
 | 
				
			||||||
 | 
					        .gpio_port = 0,                        \
 | 
				
			||||||
 | 
					        .a_gpio_number = 0,                    \
 | 
				
			||||||
 | 
					        .b_gpio_number = 0,                    \
 | 
				
			||||||
 | 
					        .pullup = false,                       \
 | 
				
			||||||
 | 
					        .encoder_min_value = -100,             \
 | 
				
			||||||
 | 
					        .encoder_max_value = 100,              \
 | 
				
			||||||
 | 
					        .encoder_step = 1,                     \
 | 
				
			||||||
 | 
					        .encoder_number = 0}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C"
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typedef struct // Structure for initial initialization of encoder.
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint8_t task_priority;     // Task priority for the encoder isr processing. @note It is not recommended to set a value less than configMAX_PRIORITIES.
 | 
				
			||||||
 | 
					        uint16_t stack_size;       // Stack size for task for the encoder isr processing processing. @note The minimum size is 124 bytes.
 | 
				
			||||||
 | 
					        uint8_t queue_size;        // Queue size for task for the encoder processing. Depends on the number of encoders.
 | 
				
			||||||
 | 
					        uint8_t gpio_port;         // Encoder GPIO port. @note Must be same for A and B GPIO.
 | 
				
			||||||
 | 
					        uint8_t a_gpio_number;     // Encoder A GPIO number.
 | 
				
			||||||
 | 
					        uint8_t b_gpio_number;     // Encoder B GPIO number.
 | 
				
			||||||
 | 
					        bool pullup;               // Using internal pullup resistors.
 | 
				
			||||||
 | 
					        int32_t encoder_min_value; // Encoder min value. @note Must be less than encoder_max_value.
 | 
				
			||||||
 | 
					        int32_t encoder_max_value; // Encoder max value. @note Must be greater than encoder_min_value.
 | 
				
			||||||
 | 
					        double encoder_step;       // Encoder step. @note Must be greater than 0.
 | 
				
			||||||
 | 
					        uint8_t encoder_number;    // Unique encoder number.
 | 
				
			||||||
 | 
					    } zh_avr_encoder_init_config_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typedef struct // Encoder handle.
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint8_t gpio_port;         // Encoder GPIO port.
 | 
				
			||||||
 | 
					        uint8_t a_gpio_number;     // Encoder A GPIO number.
 | 
				
			||||||
 | 
					        uint8_t b_gpio_number;     // Encoder B GPIO number.
 | 
				
			||||||
 | 
					        int32_t encoder_min_value; // Encoder min value.
 | 
				
			||||||
 | 
					        int32_t encoder_max_value; // Encoder max value.
 | 
				
			||||||
 | 
					        double encoder_step;       // Encoder step.
 | 
				
			||||||
 | 
					        double encoder_position;   // Encoder position.
 | 
				
			||||||
 | 
					        uint8_t encoder_number;    // Encoder unique number.
 | 
				
			||||||
 | 
					        uint8_t encoder_state;     // Encoder internal state.
 | 
				
			||||||
 | 
					        bool is_initialized;       // Encoder initialization flag.
 | 
				
			||||||
 | 
					    } zh_avr_encoder_handle_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typedef struct // Structure for sending data to the event handler when cause an interrupt. @note Should be used with zh_avr_encoder event base.
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uint8_t encoder_number;  // Encoder unique number.
 | 
				
			||||||
 | 
					        double encoder_position; // Encoder current position.
 | 
				
			||||||
 | 
					    } zh_avr_encoder_event_on_isr_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Initialize encoder.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @note The encoder will be set to the position (encoder_min_value + encoder_max_value)/2.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param[in] config Pointer to encoder initialized configuration structure. Can point to a temporary variable.
 | 
				
			||||||
 | 
					     * @param[out] handle Pointer to unique encoder handle.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @note Before initialize the encoder recommend initialize zh_avr_encoder_init_config_t structure with default values.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @code zh_avr_encoder_init_config_t config = ZH_AVR_ENCODER_INIT_CONFIG_DEFAULT() @endcode
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return AVR_OK if success or an error code otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    avr_err_t zh_avr_encoder_init(const zh_avr_encoder_init_config_t *config, zh_avr_encoder_handle_t *handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Set encoder position.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param[in, out] handle Pointer to unique encoder handle.
 | 
				
			||||||
 | 
					     * @param[in] position Encoder position (must be between encoder_min_value and encoder_max_value).
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return AVR_OK if success or an error code otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    avr_err_t zh_avr_encoder_set(zh_avr_encoder_handle_t *handle, double position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Get encoder position.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param[in] handle Pointer to unique encoder handle.
 | 
				
			||||||
 | 
					     * @param[out] position Encoder position.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return AVR_OK if success or an error code otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    avr_err_t zh_avr_encoder_get(const zh_avr_encoder_handle_t *handle, double *position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Reset encoder position.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @note The encoder will be set to the position (encoder_min_value + encoder_max_value)/2.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param[in, out] handle Pointer to unique encoder handle.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return AVR_OK if success or an error code otherwise.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    avr_err_t zh_avr_encoder_reset(zh_avr_encoder_handle_t *handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @brief Encoder ISR handler.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    BaseType_t zh_avr_encoder_isr_handler(zh_avr_encoder_handle_t *handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										1
									
								
								version.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								version.txt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					1.0.0
 | 
				
			||||||
							
								
								
									
										191
									
								
								zh_avr_encoder.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								zh_avr_encoder.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
				
			|||||||
 | 
					#include "zh_avr_encoder.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ENCODER_DIRECTION_CW 0x10
 | 
				
			||||||
 | 
					#define ENCODER_DIRECTION_CCW 0x20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const uint8_t _encoder_matrix[7][4] PROGMEM = {
 | 
				
			||||||
 | 
					    {0x03, 0x02, 0x01, 0x00},
 | 
				
			||||||
 | 
					    {0x23, 0x00, 0x01, 0x00},
 | 
				
			||||||
 | 
					    {0x13, 0x02, 0x00, 0x00},
 | 
				
			||||||
 | 
					    {0x03, 0x05, 0x04, 0x00},
 | 
				
			||||||
 | 
					    {0x03, 0x03, 0x04, 0x00},
 | 
				
			||||||
 | 
					    {0x03, 0x05, 0x03, 0x00},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TaskHandle_t zh_avr_encoder = NULL;
 | 
				
			||||||
 | 
					static QueueHandle_t _queue_handle = NULL;
 | 
				
			||||||
 | 
					static bool _is_initialized = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static avr_err_t _zh_avr_encoder_validate_config(const zh_avr_encoder_init_config_t *config);
 | 
				
			||||||
 | 
					static avr_err_t _zh_avr_encoder_configure_interrupts(const zh_avr_encoder_init_config_t *config, zh_avr_encoder_handle_t *handle);
 | 
				
			||||||
 | 
					static void _zh_avr_encoder_isr_processing_task(void *pvParameter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					avr_err_t zh_avr_encoder_init(const zh_avr_encoder_init_config_t *config, zh_avr_encoder_handle_t *handle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    avr_err_t err = _zh_avr_encoder_validate_config(config);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(err == AVR_OK, err);
 | 
				
			||||||
 | 
					    handle->encoder_number = config->encoder_number;
 | 
				
			||||||
 | 
					    handle->encoder_min_value = config->encoder_min_value;
 | 
				
			||||||
 | 
					    handle->encoder_max_value = config->encoder_max_value;
 | 
				
			||||||
 | 
					    handle->encoder_step = config->encoder_step;
 | 
				
			||||||
 | 
					    handle->encoder_position = (handle->encoder_min_value + handle->encoder_max_value) / 2;
 | 
				
			||||||
 | 
					    handle->gpio_port = config->gpio_port;
 | 
				
			||||||
 | 
					    handle->a_gpio_number = config->a_gpio_number;
 | 
				
			||||||
 | 
					    handle->b_gpio_number = config->b_gpio_number;
 | 
				
			||||||
 | 
					    err = _zh_avr_encoder_configure_interrupts(config, handle);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(err == AVR_OK, err);
 | 
				
			||||||
 | 
					    handle->is_initialized = true;
 | 
				
			||||||
 | 
					    _is_initialized = true;
 | 
				
			||||||
 | 
					    return AVR_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					avr_err_t zh_avr_encoder_set(zh_avr_encoder_handle_t *handle, double position)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(handle->is_initialized == true, AVR_FAIL);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(position <= handle->encoder_max_value && position >= handle->encoder_min_value, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    handle->encoder_position = position;
 | 
				
			||||||
 | 
					    return AVR_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					avr_err_t zh_avr_encoder_get(const zh_avr_encoder_handle_t *handle, double *position)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(handle->is_initialized == true, AVR_FAIL);
 | 
				
			||||||
 | 
					    *position = handle->encoder_position;
 | 
				
			||||||
 | 
					    return AVR_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					avr_err_t zh_avr_encoder_reset(zh_avr_encoder_handle_t *handle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(handle->is_initialized == true, AVR_FAIL);
 | 
				
			||||||
 | 
					    handle->encoder_position = (handle->encoder_min_value + handle->encoder_max_value) / 2;
 | 
				
			||||||
 | 
					    return AVR_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static avr_err_t _zh_avr_encoder_validate_config(const zh_avr_encoder_init_config_t *config)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config != NULL, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->task_priority > tskIDLE_PRIORITY && config->stack_size >= 124, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->queue_size > 0, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->encoder_max_value > config->encoder_min_value, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->encoder_step > 0, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->gpio_port >= AVR_PORTB && config->gpio_port <= AVR_PORTD, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->a_gpio_number >= 0 && config->a_gpio_number <= 7, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->b_gpio_number >= 0 && config->b_gpio_number <= 7, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    ZH_ERROR_CHECK(config->a_gpio_number != config->b_gpio_number, AVR_ERR_INVALID_ARG);
 | 
				
			||||||
 | 
					    return AVR_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static avr_err_t _zh_avr_encoder_configure_interrupts(const zh_avr_encoder_init_config_t *config, zh_avr_encoder_handle_t *handle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    switch (config->gpio_port)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case AVR_PORTB:
 | 
				
			||||||
 | 
					        DDRB &= ~((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        if (config->pullup == true)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            PORTB |= ((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PCICR |= (1 << PCIE0);
 | 
				
			||||||
 | 
					        PCMSK0 |= ((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case AVR_PORTC:
 | 
				
			||||||
 | 
					        DDRC &= ~((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        if (config->pullup == true)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            PORTC |= ((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PCICR |= (1 << PCIE1);
 | 
				
			||||||
 | 
					        PCMSK1 |= ((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case AVR_PORTD:
 | 
				
			||||||
 | 
					        DDRD &= ~((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        if (config->pullup == true)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            PORTD |= ((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PCICR |= (1 << PCIE2);
 | 
				
			||||||
 | 
					        PCMSK2 |= ((1 << config->a_gpio_number) | (1 << config->b_gpio_number));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        return AVR_ERR_INVALID_ARG;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (_is_initialized == false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        _queue_handle = xQueueCreate(config->queue_size, sizeof(zh_avr_encoder_handle_t));
 | 
				
			||||||
 | 
					        ZH_ERROR_CHECK(_queue_handle != NULL, AVR_ERR_NO_MEM);
 | 
				
			||||||
 | 
					        BaseType_t x_err = xTaskCreate(_zh_avr_encoder_isr_processing_task, "zh_avr_encoder", config->stack_size, NULL, config->task_priority, &zh_avr_encoder);
 | 
				
			||||||
 | 
					        if (x_err != pdPASS)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            vQueueDelete(_queue_handle);
 | 
				
			||||||
 | 
					            return AVR_FAIL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return AVR_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BaseType_t zh_avr_encoder_isr_handler(zh_avr_encoder_handle_t *handle)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 | 
				
			||||||
 | 
					    uint8_t temp = 0;
 | 
				
			||||||
 | 
					    switch (handle->gpio_port)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    case AVR_PORTB:
 | 
				
			||||||
 | 
					        temp = pgm_read_byte(&_encoder_matrix[handle->encoder_state & 0x0F][(((PINB & (1 << handle->b_gpio_number)) == 0 ? 0 : 1) << 1) | ((PINB & (1 << handle->a_gpio_number)) == 0 ? 0 : 1)]);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case AVR_PORTC:
 | 
				
			||||||
 | 
					        temp = pgm_read_byte(&_encoder_matrix[handle->encoder_state & 0x0F][(((PINC & (1 << handle->b_gpio_number)) == 0 ? 0 : 1) << 1) | ((PINC & (1 << handle->a_gpio_number)) == 0 ? 0 : 1)]);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case AVR_PORTD:
 | 
				
			||||||
 | 
					        temp = pgm_read_byte(&_encoder_matrix[handle->encoder_state & 0x0F][(((PIND & (1 << handle->b_gpio_number)) == 0 ? 0 : 1) << 1) | ((PIND & (1 << handle->a_gpio_number)) == 0 ? 0 : 1)]);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (temp != handle->encoder_state)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        handle->encoder_state = temp;
 | 
				
			||||||
 | 
					        switch (handle->encoder_state & 0x30)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					        case ENCODER_DIRECTION_CW:
 | 
				
			||||||
 | 
					            if (handle->encoder_position < handle->encoder_max_value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                handle->encoder_position = handle->encoder_position + handle->encoder_step;
 | 
				
			||||||
 | 
					                if (handle->encoder_position > handle->encoder_max_value)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    handle->encoder_position = handle->encoder_max_value;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                xQueueSendFromISR(_queue_handle, handle, &xHigherPriorityTaskWoken);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        case ENCODER_DIRECTION_CCW:
 | 
				
			||||||
 | 
					            if (handle->encoder_position > handle->encoder_min_value)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                handle->encoder_position = handle->encoder_position - handle->encoder_step;
 | 
				
			||||||
 | 
					                if (handle->encoder_position < handle->encoder_min_value)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    handle->encoder_position = handle->encoder_min_value;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                xQueueSendFromISR(_queue_handle, handle, &xHigherPriorityTaskWoken);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return xHigherPriorityTaskWoken;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void _zh_avr_encoder_isr_processing_task(void *pvParameter)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    zh_avr_encoder_handle_t queue = {0};
 | 
				
			||||||
 | 
					    zh_avr_encoder_event_on_isr_t event = {0};
 | 
				
			||||||
 | 
					    while (xQueueReceive(_queue_handle, &queue, portMAX_DELAY) == pdTRUE)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        event.encoder_number = queue.encoder_number;
 | 
				
			||||||
 | 
					        event.encoder_position = queue.encoder_position;
 | 
				
			||||||
 | 
					        extern void zh_avr_encoder_event_handler(zh_avr_encoder_event_on_isr_t * event);
 | 
				
			||||||
 | 
					        zh_avr_encoder_event_handler(&event);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vTaskDelete(NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user