Browse Source

Merge branch 'dev'

TelenkovDmitry 1 year ago
parent
commit
84bf234713

+ 101 - 31
fw/modules/io/input.c

@@ -3,19 +3,20 @@
 #include "settings_api.h"
 #include "FreeRTOS.h"
 #include "task.h"
+#include "mux.h"
 #include <stdio.h>
 
 
 // *port; pin; mode; port_source; pin_source; deb_counter; p_flag; cnt;
 din_t inputs[DI_NUMBER] = {
-    {GPIOB, GPIO_PINS_11, 0, 0, false, 0}, // 1   
-    {GPIOB, GPIO_PINS_10, 0, 0, false, 0}, // 2
-    {GPIOE, GPIO_PINS_14, 0, 0, false, 0}, // 3 перенесли {GPIOB, GPIO_PINS_1,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE1,  0},
-    {GPIOE, GPIO_PINS_15, 0, 0, false, 0}, // 4 перенесли {GPIOB, GPIO_PINS_0,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE0,  0},
-    {GPIOA, GPIO_PINS_3,  0, 0, false, 0}, // 5
-    {GPIOA, GPIO_PINS_2,  0, 0, false, 0}, // 6
-    {GPIOA, GPIO_PINS_1,  0, 0, false, 0}, // 7
-    {GPIOA, GPIO_PINS_0,  0, 0, false, 0}  // 8
+    {GPIOB, GPIO_PINS_11, 0, 0, 0, false, false}, // 1   
+    {GPIOB, GPIO_PINS_10, 0, 0, 0, false, false}, // 2
+    {GPIOE, GPIO_PINS_14, 0, 0, 0, false, false}, // 3 перенесли {GPIOB, GPIO_PINS_1,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE1,  0},
+    {GPIOE, GPIO_PINS_15, 0, 0, 0, false, false}, // 4 перенесли {GPIOB, GPIO_PINS_0,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE0,  0},
+    {GPIOA, GPIO_PINS_3,  0, 0, 0, false, false}, // 5
+    {GPIOA, GPIO_PINS_2,  0, 0, 0, false, false}, // 6
+    {GPIOA, GPIO_PINS_1,  0, 0, 0, false, false}, // 7
+    {GPIOA, GPIO_PINS_0,  0, 0, 0, false, false}  // 8
 };
 
 
@@ -31,7 +32,7 @@ void in_init(din_t *input)
     gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
     gpio_init_struct.gpio_pins           = input->pin;
     gpio_init(input->port, &gpio_init_struct);
-        
+
 #if 0    
     // Вход
     if (input->mode == 0)
@@ -73,9 +74,18 @@ void in_exint_init(void)
                                     EXINT_LINE_3 | EXINT_LINE_10 | 
                                     EXINT_LINE_11| EXINT_LINE_14 | EXINT_LINE_15; 
     
-    exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
+    exint_init_struct.line_polarity = EXINT_TRIGGER_BOTH_EDGE;
     exint_init(&exint_init_struct);
     
+    exint_flag_clear(EXINT_LINE_0);
+    exint_flag_clear(EXINT_LINE_1);
+    exint_flag_clear(EXINT_LINE_2);
+    exint_flag_clear(EXINT_LINE_3);
+    exint_flag_clear(EXINT_LINE_10);
+    exint_flag_clear(EXINT_LINE_11);
+    exint_flag_clear(EXINT_LINE_14);
+    exint_flag_clear(EXINT_LINE_15);
+    
     nvic_irq_enable(EXINT0_IRQn, 5, 0);
     nvic_irq_enable(EXINT1_IRQn, 5, 0);
     nvic_irq_enable(EXINT2_IRQn, 5, 0);
@@ -139,10 +149,14 @@ void input_task(void *params)
             {
                 input_state[i] = (uint16_t)gpio_input_data_bit_read(inputs[i].port, inputs[i].pin);
                 
-                if (!input_state[i])
+                if (!input_state[i]) {
                     input_state_bit &= ~(1 << i); // снять бит
-                else
+                    leds[i].state = LED_OFF;
+                }
+                else {
                     input_state_bit |= input_state[i] << i;
+                    leds[i].state = LED_ON;
+                }
             }
         }
             
@@ -159,6 +173,17 @@ inline void debounce(void)
             if (++inputs[i].cnt == settings.di_debounce[i]) {
                 inputs[i].cnt = 0;
                 inputs[i].p_flag = false;
+                
+                input_state[i] = (uint16_t)gpio_input_data_bit_read(inputs[i].port, inputs[i].pin);
+                
+                if (!input_state[i]) {
+                    input_state_bit &= ~(1 << i); // снять бит
+                    leds[i].state = LED_OFF;
+                }
+                else {
+                    input_state_bit |= input_state[i] << i;
+                    leds[i].state = LED_ON;
+                }
             }
         }
     }
@@ -172,8 +197,14 @@ void EXINT0_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_0);
         if (inputs[7].mode == 0)
             inputs[7].p_flag = true;
-        else
-            input_cnt[7]++;
+        else { 
+            if (inputs[7].cnt_flag) {
+                input_cnt[7]++;
+                inputs[7].cnt_flag = false;
+            }
+            else
+                inputs[7].cnt_flag = true;
+        }
     }
 }
 
@@ -185,8 +216,14 @@ void EXINT1_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_1);
         if (inputs[6].mode == 0)
             inputs[6].p_flag = true;
-        else
-            input_cnt[6]++;
+        else { 
+            if (inputs[6].cnt_flag) {
+                input_cnt[6]++;
+                inputs[6].cnt_flag = false;
+            }
+            else
+                inputs[6].cnt_flag = true;
+        }
     }
 }
 
@@ -198,9 +235,14 @@ void EXINT2_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_2);
         if (inputs[5].mode == 0)
             inputs[5].p_flag = true;
-        else
-            input_cnt[5]++;
-        
+        else { 
+            if (inputs[5].cnt_flag) {
+                input_cnt[5]++;
+                inputs[5].cnt_flag = false;
+            }
+            else
+                inputs[5].cnt_flag = true;
+        }
     }
 }
 
@@ -212,8 +254,14 @@ void EXINT3_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_3);
         if (inputs[4].mode == 0)
             inputs[4].p_flag = true;
-        else
-            input_cnt[4]++;
+        else { 
+            if (inputs[4].cnt_flag) {
+                input_cnt[4]++;
+                inputs[4].cnt_flag = false;
+            }
+            else
+                inputs[4].cnt_flag = true;
+        }
     }
 }
 
@@ -226,9 +274,14 @@ void EXINT15_10_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_10);
         if (inputs[1].mode == 0)
             inputs[1].p_flag = true;
-        else
-            input_cnt[1]++;
-          
+        else { 
+            if (inputs[1].cnt_flag) {
+                input_cnt[1]++;
+                inputs[1].cnt_flag = false;
+            }
+            else
+                inputs[1].cnt_flag = true;
+        }
     }
     // IN_1 GPIOB_11
     else if (exint_flag_get(EXINT_LINE_11) != RESET)  
@@ -236,8 +289,14 @@ void EXINT15_10_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_11);
         if (inputs[0].mode == 0)
             inputs[0].p_flag = true;
-        else
-            input_cnt[0]++;
+        else { 
+            if (inputs[0].cnt_flag) {
+                input_cnt[0]++;
+                inputs[0].cnt_flag = false;
+            }
+            else
+                inputs[0].cnt_flag = true;
+        }
     }
     // IN_3 GPIOE_14
     else if (exint_flag_get(EXINT_LINE_14) != RESET)  
@@ -245,9 +304,14 @@ void EXINT15_10_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_14);
         if (inputs[2].mode == 0)
             inputs[2].p_flag = true;
-        else
-            input_cnt[2]++;
-        
+        else { 
+            if (inputs[2].cnt_flag) {
+                input_cnt[2]++;
+                inputs[2].cnt_flag = false;
+            }
+            else
+                inputs[2].cnt_flag = true;
+        }
     }
     // IN_4 GPIOE_15
     else if (exint_flag_get(EXINT_LINE_15) != RESET) 
@@ -255,7 +319,13 @@ void EXINT15_10_IRQHandler(void)
         exint_flag_clear(EXINT_LINE_15);
         if (inputs[3].mode == 0)
             inputs[3].p_flag = true;
-        else
-            input_cnt[3]++;
+        else { 
+            if (inputs[3].cnt_flag) {
+                input_cnt[3]++;
+                inputs[3].cnt_flag = false;
+            }
+            else
+                inputs[3].cnt_flag = true;
+        }
     }    
 }

+ 26 - 0
fw/modules/io/io.c

@@ -5,6 +5,7 @@
 #include "input.h"
 #include "output.h"
 #include "settings_api.h"
+#include "io_utils.h"
 #include <stdio.h>
 
 
@@ -14,6 +15,11 @@ uint16_t input_state_bit;
 
 //uint16_t output_state[DO_NUMBER];     // состояние входа
 uint16_t output_state_bit;
+uint16_t output_mode_bit;
+uint16_t output_pwm[DO_NUMBER];
+uint16_t output_pwm_save[DO_NUMBER];
+uint16_t output_pwm_period[DO_NUMBER];
+uint16_t output_pwm_period_save[DO_NUMBER];
 
 // -------------------------------------------------------------------------- //
 // Текущие параметры
@@ -49,9 +55,27 @@ void io_init(void)
     }
 
     output_state_bit = settings.do_bits;
+    output_mode_bit = settings.do_mode_bits;
+    
+    // Таймер для выходов в режиме PWM
+    out_pwm_tim_init();
     
     for (int i = 0; i < DO_NUMBER; i++)
     {
+        output_pwm[i] = settings.do_pwm[i];
+        output_pwm_save[i] = settings.do_pwm_save[i];
+        output_pwm_period[i] = settings.do_pwm_period[i];
+        output_pwm_period_save[i] = settings.do_pwm_period_save[i];
+
+        if (save_mode_get()) {
+            outputs[i].pwm_duty = settings.do_pwm_save[i];
+            outputs[i].pwm_period = settings.do_pwm_period_save[i];
+        }
+        else {
+            outputs[i].pwm_duty = settings.do_pwm[i];
+            outputs[i].pwm_period = settings.do_pwm_period[i];
+        }
+        
         out_gpio_init(&outputs[i], i);
         load_sens_init(&load_sens[i]);
     }
@@ -81,6 +105,7 @@ void io_tim_init(void)
     tmr_counter_enable(TMR12, TRUE);  
 }
 
+
 void TMR8_BRK_TMR12_IRQHandler(void)
 {
     //static int i = 0;
@@ -100,3 +125,4 @@ void TMR8_BRK_TMR12_IRQHandler(void)
 #endif        
     }
 }
+

+ 12 - 1
fw/modules/io/io.h

@@ -53,8 +53,9 @@ typedef struct
     uint16_t pin;
     uint16_t mode;  // 0 - обычный вход, 1 - счетный вход
     uint32_t deb_counter;
-    bool p_flag;
     uint32_t cnt;
+    bool p_flag;
+    bool cnt_flag;
     
 } din_t;
 
@@ -64,6 +65,11 @@ typedef struct
     gpio_type *port;
     uint16_t pin;
     uint16_t mode;  // 0 - обычный выход, 1 - режим ШИМ
+    uint16_t pwm_period_cnt;
+    uint16_t pwm_duty_cnt;
+    uint16_t pwm_flag;
+    uint16_t pwm_period;
+    uint16_t pwm_duty;
     
 } out_t;
 
@@ -79,6 +85,11 @@ extern uint16_t input_state_bit;             // битовое поле
 extern uint32_t input_cnt[DI_NUMBER];       // счетчики входов
 
 extern uint16_t output_state_bit;
+extern uint16_t output_mode_bit;
+extern uint16_t output_pwm[];
+extern uint16_t output_pwm_save[];
+extern uint16_t output_pwm_period[];
+extern uint16_t output_pwm_period_save[];
 
 //uint16_t output_state[DI_NUMBER];    // состояние выхода, 0 - норма, 1 - обрыв, 2 - КЗ
 

+ 20 - 3
fw/modules/io/io_utils.c

@@ -5,25 +5,42 @@
 #include "input.h"
 #include "output.h"
 #include "settings_api.h"
+#include "mux.h"
 #include <stdio.h>
 
 
 bool save_mode = false;
+static uint16_t counter = 0;
 
 //
 void save_mode_init(void)
 {
     save_mode = settings.save_mode;
+    save_mode ? mux_led_status(false) : mux_led_status(true);
 }
 
 //
-void set_save_mode(bool state)
+void save_mode_set(bool state)
 {
     save_mode = state;
+    save_mode ? mux_led_status(false) : mux_led_status(true);
 }
 
 //
-bool get_save_mode(void)
+bool save_mode_get(void)
 {
     return save_mode;
-}
+}
+
+// Должна вызываться раз в секунду
+void save_mode_inc_cnt(void)
+{
+    bool foo = counter++ > settings.save_delay ? true : false;
+    save_mode_set(foo);
+}
+
+//
+void save_mode_reset_cnt(void)
+{
+    counter = 0;
+}

+ 7 - 2
fw/modules/io/io_utils.h

@@ -8,11 +8,16 @@
 void save_mode_init(void);
 
 //
-void set_save_mode(bool state);
+void save_mode_set(bool state);
 
 //
-bool get_save_mode(void);
+bool save_mode_get(void);
 
+//
+void save_mode_inc_cnt(void);
+
+//
+void save_mode_reset_cnt(void);
 
 #endif  // __IO_UTILS_H
 

+ 44 - 31
fw/modules/io/mux.c

@@ -6,40 +6,40 @@
 
 
 mux_channel_t leds[LED_NUMBER] = {
-                                  {"INP_1", {0, 0, 0}, LED_OFF, 0},
-                                  {"INP_2", {0, 0, 0}, LED_OFF, 0},
-                                  {"INP_3", {0, 0, 0}, LED_OFF, 0},
-                                  {"INP_4", {0, 0, 0}, LED_OFF, 0},
-
-                                  {"OUT_1_G", {1, 0, 0}, LED_OFF, 0},
-                                  {"OUT_2_G", {1, 0, 0}, LED_OFF, 0},
-                                  {"OUT_3_G", {1, 0, 0}, LED_OFF, 0},
-                                  {"OUT_4_G", {1, 0, 0}, LED_OFF, 0},
+                                  {INP_1, {0, 0, 0}, LED_OFF, 0},
+                                  {INP_2, {0, 0, 0}, LED_OFF, 0},
+                                  {INP_3, {0, 0, 0}, LED_OFF, 0},
+                                  {INP_4, {0, 0, 0}, LED_OFF, 0},
+
+                                  {INP_5, {0, 1, 1}, LED_OFF, 0},
+                                  {INP_6, {0, 1, 1}, LED_OFF, 0},
+                                  {INP_7, {0, 1, 1}, LED_OFF, 0},
+                                  {INP_8, {0, 1, 1}, LED_OFF, 0},
                                   
-                                  {"OUT_1_R", {0, 1, 0}, LED_OFF, 0},
-                                  {"OUT_2_R", {0, 1, 0}, LED_OFF, 0},
-                                  {"OUT_3_R", {0, 1, 0}, LED_OFF, 0},
-                                  {"OUT_4_R", {0, 1, 0}, LED_OFF, 0},
-
-                                  {"STATUS_G", {1, 1, 0}, LED_OFF, 0},
-                                  {"STATUS_R", {1, 1, 0}, LED_OFF, 0},
-                                  {"RX_G", {1, 1, 0}, LED_OFF, 0},
-                                  {"TX_R", {1, 1, 0}, LED_OFF, 0},
+                                  {OUT_1_G, {1, 0, 0}, LED_OFF, 0},
+                                  {OUT_2_G, {1, 0, 0}, LED_OFF, 0},
+                                  {OUT_3_G, {1, 0, 0}, LED_OFF, 0},
+                                  {OUT_4_G, {1, 0, 0}, LED_OFF, 0},
                                   
-                                  {"OUT_5_R", {0, 0, 1}, LED_OFF, 0},
-                                  {"OUT_6_R", {0, 0, 1}, LED_OFF, 0},
-                                  {"OUT_7_R", {0, 0, 1}, LED_OFF, 0},
-                                  {"OUT_8_R", {0, 0, 1}, LED_OFF, 0},
-
-                                  {"OUT_5_G", {1, 0, 1}, LED_OFF, 0},
-                                  {"OUT_6_G", {1, 0, 1}, LED_OFF, 0},
-                                  {"OUT_7_G", {1, 0, 1}, LED_OFF, 0},
-                                  {"OUT_8_G", {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_1_R, {0, 1, 0}, LED_OFF, 0},
+                                  {OUT_2_R, {0, 1, 0}, LED_OFF, 0},
+                                  {OUT_3_R, {0, 1, 0}, LED_OFF, 0},
+                                  {OUT_4_R, {0, 1, 0}, LED_OFF, 0},
+
+                                  {STATUS_G, {1, 1, 0}, LED_OFF, 0},
+                                  {STATUS_R, {1, 1, 0}, LED_OFF, 0},
+                                  {RX_G, {1, 1, 0}, LED_OFF, 0},
+                                  {TX_R, {1, 1, 0}, LED_OFF, 0},
                                   
-                                  {"INP_5", {0, 1, 1}, LED_OFF, 0},
-                                  {"INP_6", {0, 1, 1}, LED_OFF, 0},
-                                  {"INP_7", {0, 1, 1}, LED_OFF, 0},
-                                  {"INP_8", {0, 1, 1}, LED_OFF, 0}
+                                  {OUT_5_R, {0, 0, 1}, LED_OFF, 0},
+                                  {OUT_6_R, {0, 0, 1}, LED_OFF, 0},
+                                  {OUT_7_R, {0, 0, 1}, LED_OFF, 0},
+                                  {OUT_8_R, {0, 0, 1}, LED_OFF, 0},
+
+                                  {OUT_5_G, {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_6_G, {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_7_G, {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_8_G, {1, 0, 1}, LED_OFF, 0}
                                  };
 
 
@@ -159,3 +159,16 @@ void mux_led_blink(void)
     }
 }
 
+// true - normal
+// false - alarm
+void mux_led_status(bool state)
+{
+    if (state) {
+        leds[STATUS_G].state = LED_ON;
+        leds[STATUS_R].state = LED_OFF;
+    }
+    else {
+        leds[STATUS_G].state = LED_OFF;
+        leds[STATUS_R].state = LED_ON;
+    }
+}

+ 46 - 1
fw/modules/io/mux.h

@@ -1,6 +1,7 @@
 #ifndef __MUX_H
 #define __MUX_H
 
+#include <stdbool.h>
 
 //
 #define LED_NUMBER      28
@@ -27,6 +28,45 @@
 #define COL_4_RESET    GPIOB->clr = GPIO_PINS_7
 
 
+typedef enum
+{
+    INP_1 = 0, 
+    INP_2, 
+    INP_3, 
+    INP_4,
+    
+    INP_5, 
+    INP_6, 
+    INP_7, 
+    INP_8,
+    
+    OUT_1_G,
+    OUT_2_G,
+    OUT_3_G,
+    OUT_4_G,
+    
+    OUT_1_R,
+    OUT_2_R,
+    OUT_3_R,
+    OUT_4_R,
+    
+    STATUS_G,
+    STATUS_R,
+    RX_G,
+    TX_R,
+    
+    OUT_5_R,
+    OUT_6_R,
+    OUT_7_R,
+    OUT_8_R,
+    
+    OUT_5_G,
+    OUT_6_G,
+    OUT_7_G,
+    OUT_8_G,
+      
+} led_t;
+
 
 typedef enum
 {
@@ -39,7 +79,7 @@ typedef enum
 
 typedef struct 
 {
-    char            label[8];
+    led_t           name;
     uint8_t         line[3];    // [line_0, line_1, line_2]
     led_state_t     state;
     uint32_t        cnt;
@@ -65,6 +105,11 @@ void mux_led_test_init(void);
 //
 void mux_led_test_toggle(void);
 
+//
+void mux_led_status(bool state);
+
+
+extern mux_channel_t leds[];
 
 #endif  // __MUX_H
 

+ 187 - 29
fw/modules/io/output.c

@@ -8,14 +8,14 @@
 
 
 out_t outputs[DO_NUMBER] = {
-    {GPIOC, GPIO_PINS_12, 0},   // -
-    {GPIOD, GPIO_PINS_2,  0},   // -
-    {GPIOE, GPIO_PINS_6,  0},   // TMR9_CH2 (remap)
-    {GPIOC, GPIO_PINS_1,  0},   // -
-    {GPIOC, GPIO_PINS_11, 0},   // -
-    {GPIOD, GPIO_PINS_3,  0},   // -
-    {GPIOE, GPIO_PINS_5,  0},   // TMR9_CH1 (remap)
-    {GPIOC, GPIO_PINS_2,  0}    // -
+    {GPIOC, GPIO_PINS_12, 0, 0, 0, false, 0, 0},   // -
+    {GPIOD, GPIO_PINS_2,  0, 0, 0, false, 0, 0},   // -
+    {GPIOE, GPIO_PINS_6,  0, 0, 0, false, 0, 0},   // TMR9_CH2 (remap)
+    {GPIOC, GPIO_PINS_1,  0, 0, 0, false, 0, 0},   // -
+    {GPIOC, GPIO_PINS_11, 0, 0, 0, false, 0, 0},   // -
+    {GPIOD, GPIO_PINS_3,  0, 0, 0, false, 0, 0},   // -
+    {GPIOE, GPIO_PINS_5,  0, 0, 0, false, 0, 0},   // TMR9_CH1 (remap)
+    {GPIOC, GPIO_PINS_2,  0, 0, 0, false, 0, 0}    // -
 };
 
 
@@ -54,6 +54,45 @@ void out_gpio_init(out_t *out, uint8_t index)
     do_update(out, index) ;
 }
 
+//
+void do_set_common(void)
+{
+    bool flag = false;
+    
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        // 
+        if ((settings.do_bits & (1 << i)) != (output_state_bit & (1 << i))) {
+            settings.do_bits = output_state_bit;
+            flag = true;
+        } 
+        else if ((settings.do_mode_bits & (1 << i)) != (output_mode_bit & (1 << i))) {
+            settings.do_mode_bits ^= (1 << i);
+            settings.do_mode_bits = output_mode_bit;
+            flag = true;
+        }  
+        else if (settings.do_pwm[i] != output_pwm[i]) {
+            settings.do_pwm[i] = output_pwm[i];
+            flag = true;
+        }
+        else if (settings.do_pwm_save[i] != output_pwm_save[i]) {
+            settings.do_pwm_save[i] = output_pwm_save[i];
+            flag = true;
+        }
+        else if (settings.do_pwm_period [i] != output_pwm_period[i]) {
+            settings.do_pwm_period[i] = output_pwm_period[i];
+            flag = true;
+        }
+        else if (settings.do_pwm_period_save[i] != output_pwm_period_save[i]) {
+            settings.do_pwm_period_save[i] = output_pwm_period_save[i];
+            flag = true;
+        }
+ 
+        if (flag)
+            do_update(&outputs[i], i);
+    }
+}
+
 //
 void do_set(void)
 {
@@ -74,45 +113,76 @@ void do_set(void)
 }
 
 // Установка значения на выходе 
-void do_update(out_t *out, uint8_t index)
+void do_update(out_t *out, uint8_t i)
 {
     // Режим ШИМ
-    if (settings.do_mode_bits & (1 << index))   
-    {
+    if (settings.do_mode_bits & (1 << i)) {
         // Безопасный режим включен
-        if (get_save_mode()) {    
-            do_set_pwm(settings.do_pwm_save[index], index);
-        }
-        else {
-            do_set_pwm(settings.do_pwm[index], index);
-        }
+        if (save_mode_get())
+            do_set_pwm(settings.do_pwm_period_save[i], settings.do_pwm_save[i], i);
+        else
+            do_set_pwm(settings.do_pwm_period[i], settings.do_pwm[i], i);
     }
     // Режим обычного выхода
-    else    
-    {
+    else {
+        out->mode = 0;
         // Безопасный режим включен
-        if (get_save_mode()) {    
-            do_set_out(out, settings.do_save_bits & (1 << index));
-        }
-        else {
-            do_set_out(out, settings.do_bits & (1 << index));
-        }
+        if (save_mode_get())
+            do_set_out(out, settings.do_save_bits & (1 << i));
+        else
+            do_set_out(out, settings.do_bits & (1 << i));
     }
 }
 
 //
-void do_set_pwm(uint16_t pwm, uint8_t index)
+void do_set_mode(void)
+{
+    if (output_mode_bit == settings.do_mode_bits)
+        return;
+  
+    // Состояние выхода/выходов изменилось
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if ((settings.do_mode_bits & (1 << i)) != (output_mode_bit & (1 << i)))
+        {
+            settings.do_mode_bits ^= (1 << i);
+            do_update(&outputs[i], i);
+        }
+    }
+  
+    settings.do_mode_bits = output_mode_bit;
+}
+
+//#define PWM_PERIOD_TEST     20
+//#define PWM_DUTY_TEST       10
+void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index)
 {
-    // pass
+    uint16_t duty_calc;
+  
+    if (duty == 0)
+        duty_calc = 0;
+    else
+        duty_calc = (duty*period/100 < 1) ? 1 : duty*period/100;
+    
+    outputs[index].pwm_flag = false;
+    outputs[index].pwm_period_cnt = 0;
+    outputs[index].pwm_duty_cnt = 0;
+    outputs[index].pwm_period = period;
+    outputs[index].pwm_duty = duty_calc;
+    outputs[index].mode = 1;
 }
 
 //
 void do_set_out(out_t *out, uint8_t val)
 {
-    if (val)
+    if (val) {
+        gpio_bits_set(GPIOB, GPIO_PINS_15);
         gpio_bits_set(out->port, out->pin);
-    else
+    }
+    else {
+        gpio_bits_reset(GPIOB, GPIO_PINS_15);
         gpio_bits_reset(out->port, out->pin);
+    }
 }
 
 //
@@ -154,6 +224,67 @@ void out_as_pwm(void)
     tmr_counter_enable(TMR9, TRUE);
 }
 
+// Таймер для выходов в режиме PWM. Частота 10Гц.
+void out_pwm_tim_init(void)
+{
+    uint16_t prescaler_value = 0;
+    uint16_t timer_period = 1000 - 1;
+    gpio_init_type gpio_init_struct;
+    
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pins = GPIO_PINS_15;
+    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init(GPIOB, &gpio_init_struct);
+
+    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
+    
+    prescaler_value = (uint16_t)(system_core_clock / 10000) - 1;
+    tmr_base_init(TMR9, timer_period, prescaler_value);
+    
+    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
+    tmr_clock_source_div_set(TMR9, TMR_CLOCK_DIV1);
+    
+    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
+
+    tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
+    
+    tmr_counter_enable(TMR9, TRUE);
+}
+
+
+
+inline void pwm_proc(void)
+{
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if (outputs[i].mode)    // режим PWM
+        {
+            if (outputs[i].pwm_period_cnt == outputs[i].pwm_period /*PWM_PERIOD_TEST*/) {
+                outputs[i].pwm_period_cnt = 0;
+            }
+            if (outputs[i].pwm_period_cnt == 0) {
+                outputs[i].pwm_flag = false;
+                gpio_bits_set(outputs[i].port, outputs[i].pin);
+                //gpio_bits_set(GPIOB, GPIO_PINS_15);
+            }
+            if (outputs[i].pwm_duty_cnt == outputs[i].pwm_duty /*PWM_DUTY_TEST*/) {
+                outputs[i].pwm_duty_cnt = 0;
+                gpio_bits_reset(outputs[i].port, outputs[i].pin);
+                //gpio_bits_reset(GPIOB, GPIO_PINS_15);
+                outputs[i].pwm_flag = true;
+            }
+            outputs[i].pwm_period_cnt++;
+            if (outputs[i].pwm_flag == false) {
+                outputs[i].pwm_duty_cnt++;
+            }
+        }
+    }
+}
+
 //
 void load_sens_init(simple_gpio_t *sens)
 {
@@ -190,7 +321,33 @@ void out_test(void)
     }  
 }
 
+//
+void load_test(void)
+{
+    printf("LOAD_1: %u LOAD_2: %u LOAD_3: %u LOAD_4: %u LOAD_5: %u LOAD_6: %u LOAD_7: %u LOAD_8: %u\r\n", 
+           gpio_input_data_bit_read(load_sens[0].port, load_sens[0].pin),
+           gpio_input_data_bit_read(load_sens[1].port, load_sens[1].pin),
+           gpio_input_data_bit_read(load_sens[2].port, load_sens[2].pin),
+           gpio_input_data_bit_read(load_sens[3].port, load_sens[3].pin),
+           gpio_input_data_bit_read(load_sens[4].port, load_sens[4].pin),
+           gpio_input_data_bit_read(load_sens[5].port, load_sens[5].pin),
+           gpio_input_data_bit_read(load_sens[6].port, load_sens[6].pin), 
+           gpio_input_data_bit_read(load_sens[7].port, load_sens[7].pin));
+}
+
+
+//
+void TMR1_BRK_TMR9_IRQHandler(void)
+{
+    if(tmr_flag_get(TMR9, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR9, TMR_OVF_FLAG);
+        //GPIOB->odt ^= GPIO_PINS_15;
+        pwm_proc();
+    }
+}
 
+#if 0
 void TMR1_BRK_TMR9_IRQHandler(void)
 {
     static uint32_t cnt1 = 0;
@@ -209,3 +366,4 @@ void TMR1_BRK_TMR9_IRQHandler(void)
         printf("Cnt2 %u\r\n", cnt2);
     }
 }
+#endif

+ 21 - 1
fw/modules/io/output.h

@@ -5,6 +5,10 @@
 #include "io.h"
 
 
+#define PWM_PERIOD_TEST     20
+#define PWM_DUTY_TEST       18
+
+
 extern out_t outputs[];
 
 extern simple_gpio_t load_sens[];
@@ -13,6 +17,9 @@ extern simple_gpio_t load_sens[];
 //
 void out_gpio_init(out_t *out, uint8_t index);
 
+//
+void do_set_common(void);
+
 //
 void do_set(void);
 
@@ -20,19 +27,32 @@ void do_set(void);
 void do_update(out_t *out, uint8_t index);
 
 //
-void do_set_pwm(uint16_t pwm, uint8_t index);
+void do_set_mode(void);
+
+//
+void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index);
 
 //
 void do_set_out(out_t *out, uint8_t val);
 
+// 
+void out_pwm_tim_init(void);
+
 //
 void out_as_pwm(void);
 
+//
+void pwm_proc(void);
+
 //
 void load_sens_init(simple_gpio_t *sens);
 
 //
 void out_test(void);
 
+//
+void load_test(void);
+
+
 #endif  // __OUTPUT_H
 

+ 88 - 0
fw/modules/misc/misc.c

@@ -130,7 +130,95 @@ void mb_test_gpio_init(void)
     
 }
 
+//
+void pwm_test(void)
+{
+    tmr_output_config_type tmr_oc_init_structure;
+    
+    pwm_gpio_config();
+    
+    uint16_t prescaler_value = 0;
+    uint16_t pulse = 0;
+    uint16_t timer_period = 10000 - 1;
+
+    // Режим PWM
+    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
+    
+    prescaler_value = (uint16_t)(system_core_clock / 10000) - 1;
+    tmr_base_init(TMR9, timer_period, prescaler_value);
+    pulse = (uint16_t)(((uint32_t) 70 * (timer_period - 1)) / 100);   // 70%
+    
+    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
+    tmr_clock_source_div_set(TMR9, TMR_CLOCK_DIV1);
+    
+    tmr_output_default_para_init(&tmr_oc_init_structure);
+    tmr_oc_init_structure.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
+    tmr_oc_init_structure.oc_idle_state = FALSE;
+    tmr_oc_init_structure.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
+    tmr_oc_init_structure.oc_output_state = TRUE;
+    tmr_output_channel_config(TMR9, TMR_SELECT_CHANNEL_2, &tmr_oc_init_structure);
+    tmr_channel_value_set(TMR9, TMR_SELECT_CHANNEL_2, pulse);
+    tmr_output_channel_buffer_enable(TMR9, TMR_SELECT_CHANNEL_2, TRUE);
+    
+    tmr_period_buffer_enable(TMR12, TRUE);
+    
+    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
+
+    tmr_interrupt_enable(TMR9, TMR_C2_INT, TRUE);
+    
+    tmr_counter_enable(TMR9, TRUE);
+}
+
+//
+void pwm_gpio_config(void)
+{
+    gpio_init_type gpio_init_struct;
+
+    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
+    
+    gpio_default_para_init(&gpio_init_struct);
+    
+#if 0    
+    // Пин в режиме PWM таймера
+    gpio_init_struct.gpio_pins = GPIO_PINS_15;
+    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+    gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init(GPIOB, &gpio_init_struct);
+#endif    
+    
+    gpio_init_struct.gpio_pins = GPIO_PINS_15;
+    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init(GPIOB, &gpio_init_struct);
+    
+    // Простой выход
+    gpio_init_struct.gpio_pins = GPIO_PINS_13;
+    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init(GPIOB, &gpio_init_struct);
+}
+
+
+#if 0
+// Для отладки PWM режимов TMR_12
+void TMR8_BRK_TMR12_IRQHandler(void)
+{
+    if(tmr_flag_get(TMR12, TMR_C2_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR12, TMR_C2_FLAG);
 
+        GPIOB->odt ^= GPIO_PINS_13;
+    }
+}
+#endif
+
+    
 #if 0
 void USART3_IRQHandler(void)
 {

+ 5 - 0
fw/modules/misc/misc.h

@@ -21,6 +21,11 @@ void mb_tim_test(void);
 //
 void mb_test_gpio_init(void);
 
+//
+void pwm_test(void);
+
+//
+void pwm_gpio_config(void);
 
 #endif  // __MISC_H
 

+ 2 - 0
fw/modules/misc/uptime.c

@@ -1,5 +1,6 @@
 #include "uptime.h"
 #include "rtc.h"
+#include "io_utils.h"
 #include <stdio.h>
 
 
@@ -42,6 +43,7 @@ void TMR1_OVF_TMR10_IRQHandler(void)
         tmr_flag_clear(TMR10, TMR_OVF_FLAG);
         uptime++;
         rtc_unix = RTC_GetUnixTime();
+        save_mode_inc_cnt();
     }
 }
 

+ 7 - 1
fw/modules/modbus/modbus.c

@@ -10,6 +10,7 @@
 #include "tim_delay.h"
 #include "modbus_params.h"
 #include "common_gpio.h"
+#include "io_utils.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdbool.h>
@@ -267,11 +268,16 @@ eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegi
 	printf("usNRegs: %u\r\n", usNRegs);
 	printf("eMode: %u\r\n", eMode);
     printf("pucRegBuffer :%X\r\n", pucRegBuffer[0]);
-*/    
+*/  
+    
+    save_mode_reset_cnt();
+      
     mb_package_flag = true;
     
 	iRegIndex = (int)(usAddress - usRegHoldingStart);
 
+    
+    
 #if 1    
 	switch (eMode)
 	{

+ 91 - 2
fw/modules/modbus/modbus_params.c

@@ -5,6 +5,7 @@
 #include "uptime.h"
 #include "rtc.h"
 #include "input.h"
+#include "output.h"
 #include <string.h>
 
 
@@ -81,7 +82,7 @@ void mb_init_params(void)
         index++;
     }
     
-    // Нормальное состояние входов
+    // Текущее состояние выходов
     mb_param[index].reg = 0x0200;
 	mb_param[index].size = 1;
 	mb_param[index].param = (uint8_t*)&output_state_bit;  
@@ -90,6 +91,86 @@ void mb_init_params(void)
     mb_param[index].check_handler = mb_check_dummy;
     
     index++;
+    
+    // Режим работы выходов
+    mb_param[index].reg = 0x0202;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&output_mode_bit;  
+	mb_param[index].set = mb_set_do_mode;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Состояние выходов в безопасном режиме
+    mb_param[index].reg = 0x0203;
+	mb_param[index].size = 1;
+	mb_param[index].param = (uint8_t*)&settings.do_save_bits;  
+	mb_param[index].set = mb_set_do;
+    mb_param[index].get = NULL;
+    mb_param[index].check_handler = mb_check_dummy;
+    
+    index++;
+    
+    // Заполнение PWM. Регистры 0x0210 - 0x0217
+    addr = 0x0210;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    // Заполнение PWM в безопасном режиме. Регистры 0x0220 - 0x0227
+    addr = 0x0220;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm_save[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    // Период PWM. Регистры 0x0220 - 0x0227
+    addr = 0x0230;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm_period[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
+    
+    // Период PWM. Регистры 0x0220 - 0x0227
+    addr = 0x0240;
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        mb_param[index].reg = addr;
+        mb_param[index].size = 1;
+        mb_param[index].param = (uint8_t*)&output_pwm_period_save[i];  // Счетчик ипульсов
+        mb_param[index].set = mb_set_do;
+        mb_param[index].get = NULL;
+        mb_param[index].check_handler = mb_check_dummy;
+        
+        addr++;
+        index++;
+    }
 }
 
 
@@ -206,7 +287,15 @@ mb_delay_action_t mb_set_din_mode(void)
 //
 mb_delay_action_t mb_set_do(void)
 {
-    do_set();
+    //do_set();
+    do_set_common();
+    return MB_NO_ACTION;
+}
+
+//
+mb_delay_action_t mb_set_do_mode(void)
+{
+    do_set_mode();
     return MB_NO_ACTION;
 }
 

+ 3 - 1
fw/modules/modbus/modbus_params.h

@@ -9,7 +9,7 @@
 #include <stdbool.h>
 
 
-#define MB_PARAM_MAX			20
+#define MB_PARAM_MAX			54
 
 
 //
@@ -62,6 +62,8 @@ mb_delay_action_t mb_set_din_mode(void);
 //
 mb_delay_action_t mb_set_do(void);
 
+//
+mb_delay_action_t mb_set_do_mode(void);
 
 // -------------------------------------------------------------------------- //
 //                      Проверка параметров                                   //

+ 7 - 2
fw/modules/settings/settings_api.c

@@ -123,6 +123,9 @@ void settings_set_all_default(void)
     // Безопасный режим
     settings.save_mode = 1; 
     
+    // Время ожидания опроса (сек.)
+    settings.save_delay = 60;
+    
 #if 0  
     SETTINGS_SetWebParamsDef();
     SETTINGS_SetTempWebParamsDef();
@@ -241,8 +244,10 @@ void settings_do_def(settings_t *settings)
     
     for (uint8_t i = 0; i < DO_NUMBER; i++)
     {
-        settings->do_pwm[i] = 50;
-        settings->do_pwm_save[i] = 50; // значение на выходах в бесопасном режиме работы
+        settings->do_pwm[i] = 30;
+        settings->do_pwm_save[i] = 30; // значение на выходах в бесопасном режиме работы
+        settings->do_pwm_period[i] = 50;
+        settings->do_pwm_period_save[i] = 50;
     }
 }
 

+ 6 - 2
fw/modules/settings/settings_api.h

@@ -81,10 +81,14 @@ typedef struct
     uint16_t    do_mode_bits;       // режим работы выхода 0 - выход, 1 - ШИМ
     uint16_t    do_bits;            // последнее сохраненное значение на выходах
     uint16_t    do_save_bits;       // значение на выходах в бесопасном режиме работы
-    uint16_t    do_pwm[DO_NUMBER];  // значение выходов в режиме ШИМ
-    uint16_t    do_pwm_save[DO_NUMBER]; // значение выходов в режиме ШИМ в безопасном режиме
+    uint16_t    do_pwm[DO_NUMBER];  // значение заполнения ШИМ
+    uint16_t    do_pwm_save[DO_NUMBER]; // значение заполнения ШИМ в безопасном режиме
+    uint16_t    do_pwm_period[DO_NUMBER];  // период ШИМ в [0.1с (10..1000)]
+    uint16_t    do_pwm_period_save[DO_NUMBER]; // период ШИМ в безопасном режиме [0.1с (10..1000)]
     
     bool        save_mode;          // безопасный режим, 0 - выкл, 1 - вкл
+    uint16_t    save_delay;         // время ожидания опроса (сек.)
+    
     
 } settings_t;
 

+ 9 - 4
fw/user/main.c

@@ -45,11 +45,11 @@ int main(void)
     
     xTaskCreate(init_task, "init_task", 10*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
-    xTaskCreate(test_hw_task, "hw_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    //xTaskCreate(test_hw_task, "hw_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
     xTaskCreate(test_gpio, "gpio_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
-    xTaskCreate(input_task, "input_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
+    //xTaskCreate(input_task, "input_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
     xTaskCreate(misc_task, "misc_task", 2*configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL);
     
@@ -90,7 +90,7 @@ void init_task(void *argument)
 
     save_mode_init();
     // TODO Для теста отключаем безопасный режим работы
-    set_save_mode(false);   
+    save_mode_set(false);   
     io_port_init();
     in_exint_init();
     cm_gpio_init();
@@ -126,6 +126,9 @@ void init_task(void *argument)
     
     update_reset_boot_try();    
     
+// -------------------------------------------------------------------------- //    
+// Тесты
+    //pwm_test(); // тесы PWM
     
 // -------------------------------------------------------------------------- //    
 // RNDIS
@@ -178,7 +181,7 @@ void soft_wdt(void *params)
     for (;;)
     {
         extern_wdt_togle(); // extern WDT
-        vTaskDelay(500);
+        vTaskDelay(100);
     }
 }
 
@@ -192,8 +195,10 @@ void test_gpio(void *params)
         vTaskDelay(1000);
         //io_test();
         //out_test();
+        //load_test();
         
         //printf("HW rev: %u\r\n", cm_gpio_get_rev());
+        printf("Save mode: %u\r\n", save_mode_get());
     }
 }
 

+ 331 - 0
iap/modules/io/input.c

@@ -0,0 +1,331 @@
+#include "at32f403a_407.h"
+#include "input.h"
+#include "settings_api.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "mux.h"
+#include <stdio.h>
+
+
+// *port; pin; mode; port_source; pin_source; deb_counter; p_flag; cnt;
+din_t inputs[DI_NUMBER] = {
+    {GPIOB, GPIO_PINS_11, 0, 0, 0, false, false}, // 1   
+    {GPIOB, GPIO_PINS_10, 0, 0, 0, false, false}, // 2
+    {GPIOE, GPIO_PINS_14, 0, 0, 0, false, false}, // 3 перенесли {GPIOB, GPIO_PINS_1,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE1,  0},
+    {GPIOE, GPIO_PINS_15, 0, 0, 0, false, false}, // 4 перенесли {GPIOB, GPIO_PINS_0,  1, GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE0,  0},
+    {GPIOA, GPIO_PINS_3,  0, 0, 0, false, false}, // 5
+    {GPIOA, GPIO_PINS_2,  0, 0, 0, false, false}, // 6
+    {GPIOA, GPIO_PINS_1,  0, 0, 0, false, false}, // 7
+    {GPIOA, GPIO_PINS_0,  0, 0, 0, false, false}  // 8
+};
+
+
+//
+void in_init(din_t *input)
+{
+    gpio_init_type gpio_init_struct;
+
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init_struct.gpio_pins           = input->pin;
+    gpio_init(input->port, &gpio_init_struct);
+
+#if 0    
+    // Вход
+    if (input->mode == 0)
+    {
+        gpio_default_para_init(&gpio_init_struct);
+        
+        gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+        gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
+        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+        gpio_init_struct.gpio_pins           = input->pin;
+        gpio_init(input->port, &gpio_init_struct); 
+    }
+    // Счетный вход
+    else if (input->mode == 1)
+    {
+    }
+#endif
+}
+
+//
+void in_exint_init(void)
+{
+    exint_init_type exint_init_struct;
+    
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE11); // 11
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOB, GPIO_PINS_SOURCE10); // 10
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOE, GPIO_PINS_SOURCE14); // 14
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOE, GPIO_PINS_SOURCE15); // 15
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE3);  // 3
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE2);  // 2
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE1);  // 1
+    gpio_exint_line_config(GPIO_PORT_SOURCE_GPIOA, GPIO_PINS_SOURCE0);  // 0
+    
+    exint_default_para_init(&exint_init_struct);
+    
+    exint_init_struct.line_enable = TRUE;
+    exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
+    exint_init_struct.line_select = EXINT_LINE_0 | EXINT_LINE_1 | EXINT_LINE_2 |
+                                    EXINT_LINE_3 | EXINT_LINE_10 | 
+                                    EXINT_LINE_11| EXINT_LINE_14 | EXINT_LINE_15; 
+    
+    exint_init_struct.line_polarity = EXINT_TRIGGER_BOTH_EDGE;
+    exint_init(&exint_init_struct);
+    
+    exint_flag_clear(EXINT_LINE_0);
+    exint_flag_clear(EXINT_LINE_1);
+    exint_flag_clear(EXINT_LINE_2);
+    exint_flag_clear(EXINT_LINE_3);
+    exint_flag_clear(EXINT_LINE_10);
+    exint_flag_clear(EXINT_LINE_11);
+    exint_flag_clear(EXINT_LINE_14);
+    exint_flag_clear(EXINT_LINE_15);
+    
+    nvic_irq_enable(EXINT0_IRQn, 5, 0);
+    nvic_irq_enable(EXINT1_IRQn, 5, 0);
+    nvic_irq_enable(EXINT2_IRQn, 5, 0);
+    nvic_irq_enable(EXINT3_IRQn, 5, 0);
+    nvic_irq_enable(EXINT15_10_IRQn, 5, 0);
+}
+
+//
+void in_set(void)
+{
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        if ((settings.di_mode_bits & (1 << i)) != inputs[i].mode) 
+        {
+            inputs[i].mode = settings.di_mode_bits & (1 << i);
+            if (inputs[i].mode == 0) 
+            {
+                inputs[i].cnt = 0;
+                inputs[i].p_flag = false;
+                input_cnt[i] = 0;
+            }
+            else
+            {
+                input_state_bit &= ~(1 << i);
+            }
+        }
+    }
+}
+
+//
+void io_test(void)
+{
+#if 0  
+    printf("IN_1: %u IN_2: %u IN_3: %u IN_4: %u IN_5: %u IN_6: %u IN_7: %u IN_8: %u\r\n", 
+           gpio_input_data_bit_read(inputs[0].port, inputs[0].pin),
+           gpio_input_data_bit_read(inputs[1].port, inputs[1].pin),
+           gpio_input_data_bit_read(inputs[2].port, inputs[2].pin),
+           gpio_input_data_bit_read(inputs[3].port, inputs[3].pin),
+           gpio_input_data_bit_read(inputs[4].port, inputs[4].pin),
+           gpio_input_data_bit_read(inputs[5].port, inputs[5].pin),
+           gpio_input_data_bit_read(inputs[6].port, inputs[6].pin), 
+           gpio_input_data_bit_read(inputs[7].port, inputs[7].pin));
+#endif    
+    
+    printf("IN_1: %u IN_2: %u IN_3: %u IN_4: %u IN_5: %u IN_6: %u IN_7: %u IN_8: %u\r\n", 
+           input_cnt[0], input_cnt[1], input_cnt[2], input_cnt[3], 
+           input_cnt[4], input_cnt[5], input_cnt[6], input_cnt[7]);
+    
+}
+
+//
+void input_task(void *params)
+{
+    for (;;)
+    {
+        
+        for (int i = 0; i < DI_NUMBER; i++)
+        {
+            // Режим обычного входа
+            if (inputs[i].mode == 0)
+            {
+                input_state[i] = (uint16_t)gpio_input_data_bit_read(inputs[i].port, inputs[i].pin);
+                
+                if (!input_state[i]) {
+                    input_state_bit &= ~(1 << i); // снять бит
+                    leds[i].state = LED_OFF;
+                }
+                else {
+                    input_state_bit |= input_state[i] << i;
+                    leds[i].state = LED_ON;
+                }
+            }
+        }
+            
+        vTaskDelay(100);
+    }
+}
+
+//
+inline void debounce(void)
+{
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        if ((inputs[i].p_flag) && (inputs[i].mode == 0)){
+            if (++inputs[i].cnt == settings.di_debounce[i]) {
+                inputs[i].cnt = 0;
+                inputs[i].p_flag = false;
+                
+                input_state[i] = (uint16_t)gpio_input_data_bit_read(inputs[i].port, inputs[i].pin);
+                
+                if (!input_state[i]) {
+                    input_state_bit &= ~(1 << i); // снять бит
+                    leds[i].state = LED_OFF;
+                }
+                else {
+                    input_state_bit |= input_state[i] << i;
+                    leds[i].state = LED_ON;
+                }
+            }
+        }
+    }
+}
+
+// IN_8 GPIOA_0
+void EXINT0_IRQHandler(void)
+{
+    if (exint_flag_get(EXINT_LINE_0) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_0);
+        if (inputs[7].mode == 0)
+            inputs[7].p_flag = true;
+        else { 
+            if (inputs[7].cnt_flag) {
+                input_cnt[7]++;
+                inputs[7].cnt_flag = false;
+            }
+            else
+                inputs[7].cnt_flag = true;
+        }
+    }
+}
+
+// IN_7 GPIOA_1
+void EXINT1_IRQHandler(void)
+{
+    if(exint_flag_get(EXINT_LINE_1) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_1);
+        if (inputs[6].mode == 0)
+            inputs[6].p_flag = true;
+        else { 
+            if (inputs[6].cnt_flag) {
+                input_cnt[6]++;
+                inputs[6].cnt_flag = false;
+            }
+            else
+                inputs[6].cnt_flag = true;
+        }
+    }
+}
+
+// IN_6 GPIOA_2
+void EXINT2_IRQHandler(void)
+{
+    if(exint_flag_get(EXINT_LINE_2) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_2);
+        if (inputs[5].mode == 0)
+            inputs[5].p_flag = true;
+        else { 
+            if (inputs[5].cnt_flag) {
+                input_cnt[5]++;
+                inputs[5].cnt_flag = false;
+            }
+            else
+                inputs[5].cnt_flag = true;
+        }
+    }
+}
+
+// IN_5 GPIOA_3
+void EXINT3_IRQHandler(void)
+{
+    if(exint_flag_get(EXINT_LINE_3) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_3);
+        if (inputs[4].mode == 0)
+            inputs[4].p_flag = true;
+        else { 
+            if (inputs[4].cnt_flag) {
+                input_cnt[4]++;
+                inputs[4].cnt_flag = false;
+            }
+            else
+                inputs[4].cnt_flag = true;
+        }
+    }
+}
+
+// IN_1, IN_2, IN_3, IN_4
+void EXINT15_10_IRQHandler(void)
+{
+    // IN_2 GPIOB_10
+    if (exint_flag_get(EXINT_LINE_10) != RESET)  
+    {
+        exint_flag_clear(EXINT_LINE_10);
+        if (inputs[1].mode == 0)
+            inputs[1].p_flag = true;
+        else { 
+            if (inputs[1].cnt_flag) {
+                input_cnt[1]++;
+                inputs[1].cnt_flag = false;
+            }
+            else
+                inputs[1].cnt_flag = true;
+        }
+    }
+    // IN_1 GPIOB_11
+    else if (exint_flag_get(EXINT_LINE_11) != RESET)  
+    {
+        exint_flag_clear(EXINT_LINE_11);
+        if (inputs[0].mode == 0)
+            inputs[0].p_flag = true;
+        else { 
+            if (inputs[0].cnt_flag) {
+                input_cnt[0]++;
+                inputs[0].cnt_flag = false;
+            }
+            else
+                inputs[0].cnt_flag = true;
+        }
+    }
+    // IN_3 GPIOE_14
+    else if (exint_flag_get(EXINT_LINE_14) != RESET)  
+    {
+        exint_flag_clear(EXINT_LINE_14);
+        if (inputs[2].mode == 0)
+            inputs[2].p_flag = true;
+        else { 
+            if (inputs[2].cnt_flag) {
+                input_cnt[2]++;
+                inputs[2].cnt_flag = false;
+            }
+            else
+                inputs[2].cnt_flag = true;
+        }
+    }
+    // IN_4 GPIOE_15
+    else if (exint_flag_get(EXINT_LINE_15) != RESET) 
+    {
+        exint_flag_clear(EXINT_LINE_15);
+        if (inputs[3].mode == 0)
+            inputs[3].p_flag = true;
+        else { 
+            if (inputs[3].cnt_flag) {
+                input_cnt[3]++;
+                inputs[3].cnt_flag = false;
+            }
+            else
+                inputs[3].cnt_flag = true;
+        }
+    }    
+}

+ 30 - 0
iap/modules/io/input.h

@@ -0,0 +1,30 @@
+#ifndef __INPUT_H
+#define __INPUT_H
+
+
+#include "io.h"
+
+
+extern din_t inputs[];
+
+//
+void in_init(din_t *input);
+
+//
+void in_exint_init(void);
+
+//
+void in_set(void);
+
+//
+void io_test(void);
+
+//
+void input_task(void *params);
+
+//
+void debounce(void);
+
+
+#endif  // __INPUT_H
+

+ 128 - 0
iap/modules/io/io.c

@@ -0,0 +1,128 @@
+#include "at32f403a_407.h"
+#include "io.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "input.h"
+#include "output.h"
+#include "settings_api.h"
+#include "io_utils.h"
+#include <stdio.h>
+
+
+uint16_t input_state[DI_NUMBER];     // состояние входа
+uint16_t input_state_bit;
+
+
+//uint16_t output_state[DO_NUMBER];     // состояние входа
+uint16_t output_state_bit;
+uint16_t output_mode_bit;
+uint16_t output_pwm[DO_NUMBER];
+uint16_t output_pwm_save[DO_NUMBER];
+uint16_t output_pwm_period[DO_NUMBER];
+uint16_t output_pwm_period_save[DO_NUMBER];
+
+// -------------------------------------------------------------------------- //
+// Текущие параметры
+
+//uint16_t input_state[DI_NUMBER];     // состояние входа
+uint32_t input_cnt[DI_NUMBER];       // счетчики входов
+
+
+//
+void io_port_init(void)
+{
+    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_GPIOD_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);
+    
+    crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);
+    
+    crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
+    pwc_battery_powered_domain_access(TRUE);
+    
+    io_tim_init();
+}
+
+//
+void io_init(void)
+{
+    for (int i = 0; i < DI_NUMBER; i++)
+    {
+        in_init(&inputs[i]);
+    }
+
+    output_state_bit = settings.do_bits;
+    output_mode_bit = settings.do_mode_bits;
+    
+    // Таймер для выходов в режиме PWM
+    out_pwm_tim_init();
+    
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        output_pwm[i] = settings.do_pwm[i];
+        output_pwm_save[i] = settings.do_pwm_save[i];
+        output_pwm_period[i] = settings.do_pwm_period[i];
+        output_pwm_period_save[i] = settings.do_pwm_period_save[i];
+
+        if (save_mode_get()) {
+            outputs[i].pwm_duty = settings.do_pwm_save[i];
+            outputs[i].pwm_period = settings.do_pwm_period_save[i];
+        }
+        else {
+            outputs[i].pwm_duty = settings.do_pwm[i];
+            outputs[i].pwm_period = settings.do_pwm_period[i];
+        }
+        
+        out_gpio_init(&outputs[i], i);
+        load_sens_init(&load_sens[i]);
+    }
+}
+
+// Таймер для антидребезга
+void io_tim_init(void)
+{
+    crm_clocks_freq_type crm_clocks_freq_struct = {0};
+    
+    crm_clocks_freq_get(&crm_clocks_freq_struct);
+    
+    nvic_irq_disable(TMR8_BRK_TMR12_IRQn);
+    
+    crm_periph_clock_enable(CRM_TMR12_PERIPH_CLOCK, TRUE);
+
+    // 1 Hz
+    tmr_base_init(TMR12, 9, (crm_clocks_freq_struct.ahb_freq / 10000) - 1);
+    tmr_cnt_dir_set(TMR12, TMR_COUNT_UP);
+    
+    NVIC_ClearPendingIRQ(TMR8_BRK_TMR12_IRQn);
+    nvic_irq_enable(TMR8_BRK_TMR12_IRQn, 5, 0);
+    
+    tmr_flag_clear(TMR12, TMR_OVF_FLAG);
+    tmr_interrupt_enable(TMR12, TMR_OVF_INT, TRUE);
+    tmr_counter_value_set(TMR12, 0);
+    tmr_counter_enable(TMR12, TRUE);  
+}
+
+
+void TMR8_BRK_TMR12_IRQHandler(void)
+{
+    //static int i = 0;
+    //static int cnt = 0;
+
+    if(tmr_flag_get(TMR12, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR12, TMR_OVF_FLAG);
+
+        debounce();
+#if 0        
+        if (i++ == 1000) {
+            i = 0;
+            cnt++;
+            printf("CNT: %u\r\n");
+        }
+#endif        
+    }
+}
+

+ 140 - 0
iap/modules/io/io.h

@@ -0,0 +1,140 @@
+#ifndef __IO_H
+#define __IO_H
+
+#include <stdbool.h>
+
+// Период опроса входов 100 мс
+
+// -------------------------------------------------------------------------- //
+// Дискретые входы
+
+#define DI_NUMBER       8   // Количество входов
+
+#define DI_MODE_IN      0   // Режим обычного входа
+
+#define DI_MODE_CNT     1   // Режим счетного входа
+
+
+// -------------------------------------------------------------------------- //
+// Выходы
+#define DO_NUMBER       8    // Количество выходов
+
+#define DEBOUNCE_CNT    50
+
+// Прочие параметры из других модулей для передачи по modbus
+
+//uint32_t uptime;
+
+
+// -------------------------------------------------------------------------- //
+
+//
+void io_port_init(void);
+
+//
+void io_init(void);
+
+//
+void io_tim_init(void);
+
+// -------------------------------------------------------------------------- //
+
+typedef struct
+{
+    gpio_type *port;
+    uint16_t pin;
+    
+} simple_gpio_t;
+
+
+typedef struct 
+{
+    gpio_type *port;
+    uint16_t pin;
+    uint16_t mode;  // 0 - обычный вход, 1 - счетный вход
+    uint32_t deb_counter;
+    uint32_t cnt;
+    bool p_flag;
+    bool cnt_flag;
+    
+} din_t;
+
+
+typedef struct
+{
+    gpio_type *port;
+    uint16_t pin;
+    uint16_t mode;  // 0 - обычный выход, 1 - режим ШИМ
+    uint16_t pwm_period_cnt;
+    uint16_t pwm_duty_cnt;
+    uint16_t pwm_flag;
+    uint16_t pwm_period;
+    uint16_t pwm_duty;
+    
+} out_t;
+
+
+
+
+// -------------------------------------------------------------------------- //
+// Текущие параметры
+
+extern uint16_t input_state[DI_NUMBER];      // состояние входа
+extern uint16_t input_state_bit;             // битовое поле
+
+extern uint32_t input_cnt[DI_NUMBER];       // счетчики входов
+
+extern uint16_t output_state_bit;
+extern uint16_t output_mode_bit;
+extern uint16_t output_pwm[];
+extern uint16_t output_pwm_save[];
+extern uint16_t output_pwm_period[];
+extern uint16_t output_pwm_period_save[];
+
+//uint16_t output_state[DI_NUMBER];    // состояние выхода, 0 - норма, 1 - обрыв, 2 - КЗ
+
+
+// -------------------------------------------------------------------------- //
+// Структуры настроек. Хранятся во внутренней памяти контроллера.
+
+
+//
+// контроль состояний - обрыв, КЗ, норма
+typedef struct
+{
+    uint16_t state;         // состояние выхода
+    uint16_t pwm;           // 
+    uint16_t mode;          // режим работы, 0 - выход, 1 - PWM
+    uint16_t smode_state;   // значение в безопасном режиме,
+                            // 0 - разомкнут, 1 - замкнут
+    uint16_t smode_pwm;     // значение PWM в безопасном режиме (%)
+    uint16_t normal_state;  // нормальное состояние выхода
+                            // 0 - разомкнут, 1 - замкнут
+} output_t;
+
+
+typedef struct
+{
+    uint16_t smode;         // безопасный режим 0 - включен, 1 - выключен
+    uint16_t com_timeout;   // время ожидания запроса от мастера
+} system_t;
+
+
+// Структура системных настроек
+/*
+typedef struct 
+{
+	uint16_t        model;			// Модель
+	uint32_t        proddate;		// Дата производства
+	uint32_t        serial;			// Серийный номер
+	uint8_t         fw_version[8];	// Версия ПО
+	uint8_t         test_state;		// Статус тестирования
+	
+} sys_settings_t;
+
+*/
+
+
+
+#endif  // __IO_H
+

+ 46 - 0
iap/modules/io/io_utils.c

@@ -0,0 +1,46 @@
+#include "at32f403a_407.h"
+#include "io_utils.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "input.h"
+#include "output.h"
+#include "settings_api.h"
+#include "mux.h"
+#include <stdio.h>
+
+
+bool save_mode = false;
+static uint16_t counter = 0;
+
+//
+void save_mode_init(void)
+{
+    save_mode = settings.save_mode;
+    save_mode ? mux_led_status(false) : mux_led_status(true);
+}
+
+//
+void save_mode_set(bool state)
+{
+    save_mode = state;
+    save_mode ? mux_led_status(false) : mux_led_status(true);
+}
+
+//
+bool save_mode_get(void)
+{
+    return save_mode;
+}
+
+// Должна вызываться раз в секунду
+void save_mode_inc_cnt(void)
+{
+    bool foo = counter++ > settings.save_delay ? true : false;
+    save_mode_set(foo);
+}
+
+//
+void save_mode_reset_cnt(void)
+{
+    counter = 0;
+}

+ 23 - 0
iap/modules/io/io_utils.h

@@ -0,0 +1,23 @@
+#ifndef __IO_UTILS_H
+#define __IO_UTILS_H
+
+#include <stdbool.h>
+
+
+//
+void save_mode_init(void);
+
+//
+void save_mode_set(bool state);
+
+//
+bool save_mode_get(void);
+
+//
+void save_mode_inc_cnt(void);
+
+//
+void save_mode_reset_cnt(void);
+
+#endif  // __IO_UTILS_H
+

+ 174 - 0
iap/modules/io/mux.c

@@ -0,0 +1,174 @@
+#include "at32f403a_407.h"
+#include "mux.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include <stdbool.h>
+
+
+mux_channel_t leds[LED_NUMBER] = {
+                                  {INP_1, {0, 0, 0}, LED_OFF, 0},
+                                  {INP_2, {0, 0, 0}, LED_OFF, 0},
+                                  {INP_3, {0, 0, 0}, LED_OFF, 0},
+                                  {INP_4, {0, 0, 0}, LED_OFF, 0},
+
+                                  {INP_5, {0, 1, 1}, LED_OFF, 0},
+                                  {INP_6, {0, 1, 1}, LED_OFF, 0},
+                                  {INP_7, {0, 1, 1}, LED_OFF, 0},
+                                  {INP_8, {0, 1, 1}, LED_OFF, 0},
+                                  
+                                  {OUT_1_G, {1, 0, 0}, LED_OFF, 0},
+                                  {OUT_2_G, {1, 0, 0}, LED_OFF, 0},
+                                  {OUT_3_G, {1, 0, 0}, LED_OFF, 0},
+                                  {OUT_4_G, {1, 0, 0}, LED_OFF, 0},
+                                  
+                                  {OUT_1_R, {0, 1, 0}, LED_OFF, 0},
+                                  {OUT_2_R, {0, 1, 0}, LED_OFF, 0},
+                                  {OUT_3_R, {0, 1, 0}, LED_OFF, 0},
+                                  {OUT_4_R, {0, 1, 0}, LED_OFF, 0},
+
+                                  {STATUS_G, {1, 1, 0}, LED_OFF, 0},
+                                  {STATUS_R, {1, 1, 0}, LED_OFF, 0},
+                                  {RX_G, {1, 1, 0}, LED_OFF, 0},
+                                  {TX_R, {1, 1, 0}, LED_OFF, 0},
+                                  
+                                  {OUT_5_R, {0, 0, 1}, LED_OFF, 0},
+                                  {OUT_6_R, {0, 0, 1}, LED_OFF, 0},
+                                  {OUT_7_R, {0, 0, 1}, LED_OFF, 0},
+                                  {OUT_8_R, {0, 0, 1}, LED_OFF, 0},
+
+                                  {OUT_5_G, {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_6_G, {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_7_G, {1, 0, 1}, LED_OFF, 0},
+                                  {OUT_8_G, {1, 0, 1}, LED_OFF, 0}
+                                 };
+
+
+
+//
+void mux_led_init(mux_channel_t *ch)
+{
+}
+
+
+//
+void mux_gpio_init(void)
+{
+    gpio_init_type gpio_initstructure;
+  
+    
+    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
+    crm_periph_clock_enable(CRM_GPIOE_PERIPH_CLOCK, TRUE);
+    
+    // LED_COL
+    //      COL_1 - PD6
+    //      COL_2 - PD7
+    //      COL_3 - PB6
+    //      COL_4 - PB7
+    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  
+    gpio_initstructure.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;  
+    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_initstructure.gpio_pins           = GPIO_PINS_6 | GPIO_PINS_7;
+    gpio_init(GPIOB, &gpio_initstructure); 
+
+    gpio_initstructure.gpio_pins           = GPIO_PINS_6 | GPIO_PINS_7;
+    gpio_init(GPIOD, &gpio_initstructure); 
+    
+    gpio_bits_reset(GPIOB, GPIO_PINS_6 | GPIO_PINS_7);
+    gpio_bits_reset(GPIOD, GPIO_PINS_6 | GPIO_PINS_7);
+    
+    // LED_LINE (низкий уровень на пине = высокий уровень на входе MUX)
+    //      LINE_0 - PE3
+    //      LINE_1 - PE2
+    //      LINE_2 - PB9
+    gpio_initstructure.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  
+    gpio_initstructure.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_initstructure.gpio_mode           = GPIO_MODE_OUTPUT;  
+    gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_initstructure.gpio_pins           = GPIO_PINS_2 | GPIO_PINS_3;
+    gpio_init(GPIOE, &gpio_initstructure); 
+
+    gpio_initstructure.gpio_pins           = GPIO_PINS_9;
+    gpio_init(GPIOB, &gpio_initstructure);
+    
+    gpio_bits_reset(GPIOE, GPIO_PINS_2 | GPIO_PINS_3);
+    gpio_bits_reset(GPIOB, GPIO_PINS_9);
+}
+
+
+//
+void mux_led_proc(void)
+{
+    uint8_t shift = 0;
+    
+    for (uint8_t i = 0; i < LED_NUMBER/4; i++)
+    {
+        leds[shift].line[0] ? (LINE_0_RESET) : (LINE_0_SET);
+        leds[shift].line[1] ? (LINE_1_RESET) : (LINE_1_SET);
+        leds[shift].line[2] ? (LINE_2_RESET) : (LINE_2_SET);
+        
+        leds[i*4].state     == LED_ON ? (COL_1_SET) : (COL_1_RESET);
+        leds[i*4 + 1].state == LED_ON ? (COL_2_SET) : (COL_2_RESET);
+        leds[i*4 + 2].state == LED_ON ? (COL_3_SET) : (COL_3_RESET);
+        leds[i*4 + 3].state == LED_ON ? (COL_4_SET) : (COL_4_RESET);
+        
+        if (leds[i*4].state == LED_ON || leds[i*4 + 1].state == LED_ON || 
+            leds[i*4 + 2].state == LED_ON || leds[i*4 + 3].state == LED_ON) 
+        {
+            vTaskDelay(1);
+        }
+        
+        shift += 4;
+    }
+}
+
+//
+void mux_led_test_init(void)
+{
+    LINE_0_SET;
+    LINE_1_SET;
+    LINE_2_SET;
+}
+
+//
+void mux_led_test_toggle(void)
+{
+    static bool flag = false;
+    
+    if (!flag) {
+        COL_1_SET;
+        flag = true;
+    }
+    else {
+        COL_1_RESET;
+        flag = false;
+    }
+}
+
+//
+void mux_led_blink(void)
+{
+    for (int i = 0; i < LED_NUMBER; i++)
+    {
+        leds[i].state = LED_ON;
+        
+        vTaskDelay(100);
+        
+        leds[i].state = LED_OFF;
+    }
+}
+
+// true - normal
+// false - alarm
+void mux_led_status(bool state)
+{
+    if (state) {
+        leds[STATUS_G].state = LED_ON;
+        leds[STATUS_R].state = LED_OFF;
+    }
+    else {
+        leds[STATUS_G].state = LED_OFF;
+        leds[STATUS_R].state = LED_ON;
+    }
+}

+ 115 - 0
iap/modules/io/mux.h

@@ -0,0 +1,115 @@
+#ifndef __MUX_H
+#define __MUX_H
+
+#include <stdbool.h>
+
+//
+#define LED_NUMBER      28
+
+#define LINE_0_SET      GPIOE->scr = GPIO_PINS_3
+#define LINE_0_RESET    GPIOE->clr = GPIO_PINS_3
+
+#define LINE_1_SET      GPIOE->scr = GPIO_PINS_2
+#define LINE_1_RESET    GPIOE->clr = GPIO_PINS_2
+
+#define LINE_2_SET      GPIOB->scr = GPIO_PINS_9
+#define LINE_2_RESET    GPIOB->clr = GPIO_PINS_9
+
+#define COL_1_SET      GPIOD->scr = GPIO_PINS_6
+#define COL_1_RESET    GPIOD->clr = GPIO_PINS_6
+
+#define COL_2_SET      GPIOD->scr = GPIO_PINS_7
+#define COL_2_RESET    GPIOD->clr = GPIO_PINS_7
+
+#define COL_3_SET      GPIOB->scr = GPIO_PINS_6
+#define COL_3_RESET    GPIOB->clr = GPIO_PINS_6
+
+#define COL_4_SET      GPIOB->scr = GPIO_PINS_7
+#define COL_4_RESET    GPIOB->clr = GPIO_PINS_7
+
+
+typedef enum
+{
+    INP_1 = 0, 
+    INP_2, 
+    INP_3, 
+    INP_4,
+    
+    INP_5, 
+    INP_6, 
+    INP_7, 
+    INP_8,
+    
+    OUT_1_G,
+    OUT_2_G,
+    OUT_3_G,
+    OUT_4_G,
+    
+    OUT_1_R,
+    OUT_2_R,
+    OUT_3_R,
+    OUT_4_R,
+    
+    STATUS_G,
+    STATUS_R,
+    RX_G,
+    TX_R,
+    
+    OUT_5_R,
+    OUT_6_R,
+    OUT_7_R,
+    OUT_8_R,
+    
+    OUT_5_G,
+    OUT_6_G,
+    OUT_7_G,
+    OUT_8_G,
+      
+} led_t;
+
+
+typedef enum
+{
+    LED_OFF = 0, 
+    LED_ON,
+    LED_BLINK,
+    
+} led_state_t;
+
+
+typedef struct 
+{
+    led_t           name;
+    uint8_t         line[3];    // [line_0, line_1, line_2]
+    led_state_t     state;
+    uint32_t        cnt;
+    
+} mux_channel_t;
+
+
+//
+void mux_led_init(mux_channel_t *ch);
+
+//
+void mux_gpio_init(void);
+
+//
+void mux_led_proc(void);
+
+//
+void mux_led_blink(void);
+
+//
+void mux_led_test_init(void);
+
+//
+void mux_led_test_toggle(void);
+
+//
+void mux_led_status(bool state);
+
+
+extern mux_channel_t leds[];
+
+#endif  // __MUX_H
+

+ 369 - 0
iap/modules/io/output.c

@@ -0,0 +1,369 @@
+#include "at32f403a_407.h"
+#include "output.h"
+#include "FreeRTOS.h"
+#include "task.h"
+#include "settings_api.h"
+#include "io_utils.h"
+#include <stdio.h>
+
+
+out_t outputs[DO_NUMBER] = {
+    {GPIOC, GPIO_PINS_12, 0, 0, 0, false, 0, 0},   // -
+    {GPIOD, GPIO_PINS_2,  0, 0, 0, false, 0, 0},   // -
+    {GPIOE, GPIO_PINS_6,  0, 0, 0, false, 0, 0},   // TMR9_CH2 (remap)
+    {GPIOC, GPIO_PINS_1,  0, 0, 0, false, 0, 0},   // -
+    {GPIOC, GPIO_PINS_11, 0, 0, 0, false, 0, 0},   // -
+    {GPIOD, GPIO_PINS_3,  0, 0, 0, false, 0, 0},   // -
+    {GPIOE, GPIO_PINS_5,  0, 0, 0, false, 0, 0},   // TMR9_CH1 (remap)
+    {GPIOC, GPIO_PINS_2,  0, 0, 0, false, 0, 0}    // -
+};
+
+
+simple_gpio_t load_sens[DO_NUMBER] = {
+    {GPIOD, GPIO_PINS_0},
+    {GPIOD, GPIO_PINS_1},
+    {GPIOC, GPIO_PINS_13},
+    {GPIOC, GPIO_PINS_0},
+    {GPIOC, GPIO_PINS_10},
+    {GPIOD, GPIO_PINS_4},
+    {GPIOE, GPIO_PINS_4},
+    {GPIOC, GPIO_PINS_3}
+};
+
+
+
+//
+void out_gpio_init(out_t *out, uint8_t index)
+{
+    gpio_init_type gpio_init_struct;
+
+    
+    // Выход
+    if (out->mode == 0)
+    {
+        gpio_default_para_init(&gpio_init_struct);
+        
+        gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;  
+        gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+        gpio_init_struct.gpio_mode           = GPIO_MODE_OUTPUT;  
+        gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+        gpio_init_struct.gpio_pins           = out->pin;
+        gpio_init(out->port, &gpio_init_struct); 
+    }
+    
+    do_update(out, index) ;
+}
+
+//
+void do_set_common(void)
+{
+    bool flag = false;
+    
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        // 
+        if ((settings.do_bits & (1 << i)) != (output_state_bit & (1 << i))) {
+            settings.do_bits = output_state_bit;
+            flag = true;
+        } 
+        else if ((settings.do_mode_bits & (1 << i)) != (output_mode_bit & (1 << i))) {
+            settings.do_mode_bits ^= (1 << i);
+            settings.do_mode_bits = output_mode_bit;
+            flag = true;
+        }  
+        else if (settings.do_pwm[i] != output_pwm[i]) {
+            settings.do_pwm[i] = output_pwm[i];
+            flag = true;
+        }
+        else if (settings.do_pwm_save[i] != output_pwm_save[i]) {
+            settings.do_pwm_save[i] = output_pwm_save[i];
+            flag = true;
+        }
+        else if (settings.do_pwm_period [i] != output_pwm_period[i]) {
+            settings.do_pwm_period[i] = output_pwm_period[i];
+            flag = true;
+        }
+        else if (settings.do_pwm_period_save[i] != output_pwm_period_save[i]) {
+            settings.do_pwm_period_save[i] = output_pwm_period_save[i];
+            flag = true;
+        }
+ 
+        if (flag)
+            do_update(&outputs[i], i);
+    }
+}
+
+//
+void do_set(void)
+{
+    if (output_state_bit == settings.do_bits) 
+        return;
+    
+    // Состояние выхода/выходов изменилось
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if ((settings.do_bits & (1 << i)) != (output_state_bit & (1 << i))) 
+        {
+            do_update(&outputs[i], i);
+        }
+    }
+    
+    // Сохраним новое значение выходов в настройках
+    settings.do_bits = output_state_bit;
+}
+
+// Установка значения на выходе 
+void do_update(out_t *out, uint8_t i)
+{
+    // Режим ШИМ
+    if (settings.do_mode_bits & (1 << i)) {
+        // Безопасный режим включен
+        if (save_mode_get())
+            do_set_pwm(settings.do_pwm_period_save[i], settings.do_pwm_save[i], i);
+        else
+            do_set_pwm(settings.do_pwm_period[i], settings.do_pwm[i], i);
+    }
+    // Режим обычного выхода
+    else {
+        out->mode = 0;
+        // Безопасный режим включен
+        if (save_mode_get())
+            do_set_out(out, settings.do_save_bits & (1 << i));
+        else
+            do_set_out(out, settings.do_bits & (1 << i));
+    }
+}
+
+//
+void do_set_mode(void)
+{
+    if (output_mode_bit == settings.do_mode_bits)
+        return;
+  
+    // Состояние выхода/выходов изменилось
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if ((settings.do_mode_bits & (1 << i)) != (output_mode_bit & (1 << i)))
+        {
+            settings.do_mode_bits ^= (1 << i);
+            do_update(&outputs[i], i);
+        }
+    }
+  
+    settings.do_mode_bits = output_mode_bit;
+}
+
+//#define PWM_PERIOD_TEST     20
+//#define PWM_DUTY_TEST       10
+void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index)
+{
+    uint16_t duty_calc;
+  
+    if (duty == 0)
+        duty_calc = 0;
+    else
+        duty_calc = (duty*period/100 < 1) ? 1 : duty*period/100;
+    
+    outputs[index].pwm_flag = false;
+    outputs[index].pwm_period_cnt = 0;
+    outputs[index].pwm_duty_cnt = 0;
+    outputs[index].pwm_period = period;
+    outputs[index].pwm_duty = duty_calc;
+    outputs[index].mode = 1;
+}
+
+//
+void do_set_out(out_t *out, uint8_t val)
+{
+    if (val) {
+        gpio_bits_set(GPIOB, GPIO_PINS_15);
+        gpio_bits_set(out->port, out->pin);
+    }
+    else {
+        gpio_bits_reset(GPIOB, GPIO_PINS_15);
+        gpio_bits_reset(out->port, out->pin);
+    }
+}
+
+//
+void out_as_pwm(void)
+{
+    uint32_t timer_period;
+    uint16_t pwm_pulse;
+    crm_clocks_freq_type crm_clocks_freq_struct = {0};
+    tmr_output_config_type tmr_output_struct;
+    
+    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
+    
+    crm_clocks_freq_get(&crm_clocks_freq_struct);
+    
+    //timer_period = (crm_clocks_freq_struct.sclk_freq / 10 ) - 1;
+    
+    timer_period = 24000 - 1;
+    pwm_pulse = 125*timer_period/1000;
+    
+    tmr_base_init(TMR9, 24000 - 1, 1000 - 1);
+    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
+
+    tmr_output_default_para_init(&tmr_output_struct);
+    tmr_output_struct.oc_mode = TMR_OUTPUT_CONTROL_PWM_MODE_A;
+    tmr_output_struct.oc_output_state = TRUE;
+    tmr_output_struct.oc_polarity = TMR_OUTPUT_ACTIVE_HIGH;
+    tmr_output_struct.oc_idle_state = TRUE;
+    
+    tmr_output_channel_config(TMR9, TMR_SELECT_CHANNEL_1, &tmr_output_struct);
+    tmr_channel_value_set(TMR9, TMR_SELECT_CHANNEL_1, pwm_pulse);
+    
+    tmr_flag_clear(TMR9, TMR_OVF_FLAG);
+    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
+    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
+    
+    //tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
+    tmr_interrupt_enable(TMR9, TMR_C1_INT, TRUE);
+    
+    tmr_counter_enable(TMR9, TRUE);
+}
+
+// Таймер для выходов в режиме PWM. Частота 10Гц.
+void out_pwm_tim_init(void)
+{
+    uint16_t prescaler_value = 0;
+    uint16_t timer_period = 1000 - 1;
+    gpio_init_type gpio_init_struct;
+    
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pins = GPIO_PINS_15;
+    gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
+    gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
+    gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT;
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init(GPIOB, &gpio_init_struct);
+
+    crm_periph_clock_enable(CRM_TMR9_PERIPH_CLOCK, TRUE);
+    
+    prescaler_value = (uint16_t)(system_core_clock / 10000) - 1;
+    tmr_base_init(TMR9, timer_period, prescaler_value);
+    
+    tmr_cnt_dir_set(TMR9, TMR_COUNT_UP);
+    tmr_clock_source_div_set(TMR9, TMR_CLOCK_DIV1);
+    
+    nvic_irq_enable(TMR1_BRK_TMR9_IRQn, 5, 0);
+
+    tmr_interrupt_enable(TMR9, TMR_OVF_INT, TRUE);
+    
+    tmr_counter_enable(TMR9, TRUE);
+}
+
+
+
+inline void pwm_proc(void)
+{
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        if (outputs[i].mode)    // режим PWM
+        {
+            if (outputs[i].pwm_period_cnt == outputs[i].pwm_period /*PWM_PERIOD_TEST*/) {
+                outputs[i].pwm_period_cnt = 0;
+            }
+            if (outputs[i].pwm_period_cnt == 0) {
+                outputs[i].pwm_flag = false;
+                gpio_bits_set(outputs[i].port, outputs[i].pin);
+                //gpio_bits_set(GPIOB, GPIO_PINS_15);
+            }
+            if (outputs[i].pwm_duty_cnt == outputs[i].pwm_duty /*PWM_DUTY_TEST*/) {
+                outputs[i].pwm_duty_cnt = 0;
+                gpio_bits_reset(outputs[i].port, outputs[i].pin);
+                //gpio_bits_reset(GPIOB, GPIO_PINS_15);
+                outputs[i].pwm_flag = true;
+            }
+            outputs[i].pwm_period_cnt++;
+            if (outputs[i].pwm_flag == false) {
+                outputs[i].pwm_duty_cnt++;
+            }
+        }
+    }
+}
+
+//
+void load_sens_init(simple_gpio_t *sens)
+{
+    gpio_init_type gpio_init_struct;
+    
+    gpio_default_para_init(&gpio_init_struct);
+        
+    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;  
+    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;  
+    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
+    gpio_init_struct.gpio_pins           = sens->pin;
+    gpio_init(sens->port, &gpio_init_struct); 
+    
+}
+
+//
+void out_test(void)
+{
+    for (int i = 0; i < DO_NUMBER; i++)
+    {
+        outputs[i].port->odt ^= outputs[i].pin;
+        
+        printf("LOAD_1: %u LOAD_2: %u LOAD_3: %u LOAD_4: %u LOAD_5: %u LOAD_6: %u LOAD_7: %u LOAD_8: %u\r\n", 
+           gpio_input_data_bit_read(load_sens[0].port, load_sens[0].pin),
+           gpio_input_data_bit_read(load_sens[1].port, load_sens[1].pin),
+           gpio_input_data_bit_read(load_sens[2].port, load_sens[2].pin),
+           gpio_input_data_bit_read(load_sens[3].port, load_sens[3].pin),
+           gpio_input_data_bit_read(load_sens[4].port, load_sens[4].pin),
+           gpio_input_data_bit_read(load_sens[5].port, load_sens[5].pin),
+           gpio_input_data_bit_read(load_sens[6].port, load_sens[6].pin), 
+           gpio_input_data_bit_read(load_sens[7].port, load_sens[7].pin));
+        
+        vTaskDelay(500);
+    }  
+}
+
+//
+void load_test(void)
+{
+    printf("LOAD_1: %u LOAD_2: %u LOAD_3: %u LOAD_4: %u LOAD_5: %u LOAD_6: %u LOAD_7: %u LOAD_8: %u\r\n", 
+           gpio_input_data_bit_read(load_sens[0].port, load_sens[0].pin),
+           gpio_input_data_bit_read(load_sens[1].port, load_sens[1].pin),
+           gpio_input_data_bit_read(load_sens[2].port, load_sens[2].pin),
+           gpio_input_data_bit_read(load_sens[3].port, load_sens[3].pin),
+           gpio_input_data_bit_read(load_sens[4].port, load_sens[4].pin),
+           gpio_input_data_bit_read(load_sens[5].port, load_sens[5].pin),
+           gpio_input_data_bit_read(load_sens[6].port, load_sens[6].pin), 
+           gpio_input_data_bit_read(load_sens[7].port, load_sens[7].pin));
+}
+
+
+//
+void TMR1_BRK_TMR9_IRQHandler(void)
+{
+    if(tmr_flag_get(TMR9, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR9, TMR_OVF_FLAG);
+        //GPIOB->odt ^= GPIO_PINS_15;
+        pwm_proc();
+    }
+}
+
+#if 0
+void TMR1_BRK_TMR9_IRQHandler(void)
+{
+    static uint32_t cnt1 = 0;
+    static uint32_t cnt2 = 0;
+    
+    if (tmr_flag_get(TMR9, TMR_OVF_FLAG) != RESET)
+    {
+        tmr_flag_clear(TMR9, TMR_OVF_FLAG);
+        cnt1++;
+        printf("Cnt1 %u\r\n", cnt1);
+    }
+    else if (tmr_flag_get(TMR9, TMR_C1_INT) != RESET)
+    {
+        tmr_flag_clear(TMR9, TMR_C1_INT);
+        cnt2++;
+        printf("Cnt2 %u\r\n", cnt2);
+    }
+}
+#endif

+ 58 - 0
iap/modules/io/output.h

@@ -0,0 +1,58 @@
+#ifndef __OUTPUT_H
+#define __OUTPUT_H
+
+
+#include "io.h"
+
+
+#define PWM_PERIOD_TEST     20
+#define PWM_DUTY_TEST       18
+
+
+extern out_t outputs[];
+
+extern simple_gpio_t load_sens[];
+
+
+//
+void out_gpio_init(out_t *out, uint8_t index);
+
+//
+void do_set_common(void);
+
+//
+void do_set(void);
+
+// Установка значения на выходе 
+void do_update(out_t *out, uint8_t index);
+
+//
+void do_set_mode(void);
+
+//
+void do_set_pwm(uint16_t period, uint16_t duty, uint8_t index);
+
+//
+void do_set_out(out_t *out, uint8_t val);
+
+// 
+void out_pwm_tim_init(void);
+
+//
+void out_as_pwm(void);
+
+//
+void pwm_proc(void);
+
+//
+void load_sens_init(simple_gpio_t *sens);
+
+//
+void out_test(void);
+
+//
+void load_test(void);
+
+
+#endif  // __OUTPUT_H
+

BIN
output/fw.bin


File diff suppressed because it is too large
+ 377 - 540
project/ewarm/iap/iap.dep


+ 7 - 0
project/ewarm/iap/iap.ewp

@@ -373,6 +373,7 @@
                     <state>$PROJ_DIR$\..\..\..\iap\modules\modbus</state>
                     <state>$PROJ_DIR$\..\..\..\iap\modules\settings</state>
                     <state>$PROJ_DIR$\..\..\..\iap\modules\iap</state>
+                    <state>$PROJ_DIR$\..\..\..\iap\modules\io</state>
                     <state>$PROJ_DIR$\..\..\..\iap\user</state>
                     <state>$PROJ_DIR$\..\..\..\libs\thirdparty\freertos\include</state>
                     <state>$PROJ_DIR$\..\..\..\libs\thirdparty\freertos\portable\IAR\ARM_CM4F</state>
@@ -2139,6 +2140,12 @@
                     <name>$PROJ_DIR$\..\..\..\iap\modules\iap\iap.c</name>
                 </file>
             </group>
+            <group>
+                <name>io</name>
+                <file>
+                    <name>$PROJ_DIR$\..\..\..\iap\modules\io\mux.c</name>
+                </file>
+            </group>
             <group>
                 <name>modbus</name>
                 <file>

+ 6 - 0
project/ewarm/iap/iap.ewt

@@ -2379,6 +2379,12 @@
                     <name>$PROJ_DIR$\..\..\..\iap\modules\iap\iap.c</name>
                 </file>
             </group>
+            <group>
+                <name>io</name>
+                <file>
+                    <name>$PROJ_DIR$\..\..\..\iap\modules\io\mux.c</name>
+                </file>
+            </group>
             <group>
                 <name>modbus</name>
                 <file>

File diff suppressed because it is too large
+ 623 - 632
project/ewarm/module_universal_io.dep


+ 2 - 0
shared/freemodbus/port/portserial.c

@@ -6,6 +6,7 @@
 #include "port.h"
 #include "mbport.h"
 #include "tim_delay.h"
+#include "mux.h"
 #include <stdlib.h>
 #include <stdbool.h>
 
@@ -221,6 +222,7 @@ void USART3_IRQHandler(void)
     {
         if (usart_flag_get(MB_UART, USART_RDBF_FLAG) == SET) 
         {
+            leds[RX_G].state = LED_ON;
             pxMBFrameCBByteReceived();
         }
     }  

+ 2 - 0
shared/freemodbus/port/porttimer.c

@@ -4,6 +4,7 @@
 #include "port.h"
 #include "mb.h"
 #include "mbport.h"
+#include "mux.h"
 #include <stdbool.h>
 
 
@@ -50,6 +51,7 @@ void TMR7_GLOBAL_IRQHandler(void)
 
       vMBPortSetWithinException(TRUE);
       prvvTIMERExpiredISR();
+      leds[RX_G].state = LED_OFF;
       vMBPortSetWithinException(FALSE);
     }
 }

+ 7 - 4
shared/freemodbus/port/tim_delay.c

@@ -1,5 +1,6 @@
 #include "at32f403a_407.h"
 #include "tim_delay.h"
+#include "mux.h"
 
 
 static bool tx_enable = false;
@@ -13,7 +14,6 @@ void mb_helper_tim_init(uint32_t baudrate)
     foo = 1.0/((float)baudrate / 11.0);
     foo *= 2000.0; // время в мс (длительность в два символа)
     
-    
     crm_clocks_freq_type crm_clocks_freq_struct = {0};
     
     crm_clocks_freq_get(&crm_clocks_freq_struct);
@@ -63,11 +63,14 @@ void TMR6_GLOBAL_IRQHandler(void)
     if(tmr_flag_get(TMR6, TMR_OVF_FLAG) != RESET)
     {
         tmr_flag_clear(TMR6, TMR_OVF_FLAG);
-        if (tx_enable)
+        if (tx_enable) {
             usart_interrupt_enable(USART3, USART_TDBE_INT, TRUE);
-        else
+            leds[TX_R].state = LED_ON;
+        }
+        else {
             gpio_bits_reset(GPIOD, GPIO_PINS_10);
-        
+            leds[TX_R].state = LED_OFF;
+        }
         mb_helper_tim_disable();
     }
 }

Some files were not shown because too many files changed in this diff