diff --git a/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_rcc.h b/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_rcc.h index 6fc5019..8767828 100644 --- a/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_rcc.h +++ b/MCU_STM32F1xx_Matlab/Drivers/STM32F1xx_SIMULINK/stm32f1xx_matlab_rcc.h @@ -9,11 +9,11 @@ //#define AHB_Prescaler ((RCC->PLLCFGR & RCC_PLLCFGR_PLLN) >> RCC_PLLCFGR_PLLN_Pos) //#define AHB_Prescaler ((RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos) -#define HCLK_Value (double)72000000; -#define ABP1_Value (double)36000000; -#define ABP1_TIMS_Value (double)72000000; -#define ABP2_Value (double)72000000; -#define ABP2_TIMS_Value (double)72000000; +//#define HCLK_Value (double)72000000; +//#define ABP1_Value (double)36000000; +//#define ABP1_TIMS_Value (double)72000000; +//#define ABP2_Value (double)72000000; +//#define ABP2_TIMS_Value (double)72000000; /* stm32f4xx_hal_rcc.c, */ /* MCU_Periph_Simulation(), */ diff --git a/MCU_STM32F1xx_Matlab/periph_config.json b/MCU_STM32F1xx_Matlab/periph_config.json new file mode 100644 index 0000000..8d354ed --- /dev/null +++ b/MCU_STM32F1xx_Matlab/periph_config.json @@ -0,0 +1,252 @@ +{ + "RCC": { + "Defines": { + "HCLK_Clock": { + "Prompt": "HCLK Clock (Hz)", + "Def": "HCLK_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP1_Clock": { + "Prompt": "ABP1 Clock (Hz)", + "Def": "ABP1_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP1_TIMS_Clock": { + "Prompt": "ABP1 Tim's Clock (Hz)", + "Def": "ABP1_TIMS_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP2_Clock": { + "Prompt": "ABP2 Clock (Hz)", + "Def": "ABP2_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP2_TIMS_Clock": { + "Prompt": "ABP2 Tim's Clock (Hz)", + "Def": "ABP2_TIMS_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + } + } + }, + "TIM": { + "Defines": { + "TIM1_Enable": { + "Prompt": "TIM1 Enable", + "Def": "USE_TIM1", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM1_UP_TIM10_Handler": { + "Prompt": "TIM1_UP_TIM10 Handler", + "Def": "USE_TIM1_UP_TIM10_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM2_Enable": { + "Prompt": "TIM2 Enable", + "Def": "USE_TIM2", + "Type": "checkbox", + "Default": true, + "NewRow": true + }, + "TIM2_Handler": { + "Prompt": "TIM2 Handler", + "Def": "USE_TIM2_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM3_Enable": { + "Prompt": "TIM3 Enable", + "Def": "USE_TIM3", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM3_Handler": { + "Prompt": "TIM3 Handler", + "Def": "USE_TIM3_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM4_Enable": { + "Prompt": "TIM4 Enable", + "Def": "USE_TIM4", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM4_Handler": { + "Prompt": "TIM4 Handler", + "Def": "USE_TIM4_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM5_Enable": { + "Prompt": "TIM5 Enable", + "Def": "USE_TIM5", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM5_Handler": { + "Prompt": "TIM5 Handler", + "Def": "USE_TIM5_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM6_Enable": { + "Prompt": "TIM6 Enable", + "Def": "USE_TIM6", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM6_Handler": { + "Prompt": "TIM6 Handler", + "Def": "USE_TIM6_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM7_Enable": { + "Prompt": "TIM7 Enable", + "Def": "USE_TIM7", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM7_Handler": { + "Prompt": "TIM7 Handler", + "Def": "USE_TIM7_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM8_Enable": { + "Prompt": "TIM8 Enable", + "Def": "USE_TIM8", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM8_UP_TIM13_Handler": { + "Prompt": "TIM8_UP_TIM13 Handler", + "Def": "USE_TIM8_UP_TIM13_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM9_Enable": { + "Prompt": "TIM9 Enable", + "Def": "USE_TIM9", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM1_BRK_TIM9_Handler": { + "Prompt": "TIM1_BRK_TIM9 Handler", + "Def": "USE_TIM1_BRK_TIM9_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM10_Enable": { + "Prompt": "TIM10 Enable", + "Def": "USE_TIM10", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM11_Enable": { + "Prompt": "TIM11 Enable", + "Def": "USE_TIM11", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM1_TRG_COM_TIM11_Handler": { + "Prompt": "TIM1_TRG_COM_TIM11 Handler", + "Def": "USE_TIM1_TRG_COM_TIM11_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM12_Enable": { + "Prompt": "TIM12 Enable", + "Def": "USE_TIM12", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM8_BRK_TIM12_Handler": { + "Prompt": "TIM8_BRK_TIM12 Handler", + "Def": "USE_TIM8_BRK_TIM12_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM13_Enable": { + "Prompt": "TIM13 Enable", + "Def": "USE_TIM13", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM14_Enable": { + "Prompt": "TIM14 Enable", + "Def": "USE_TIM14", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM8_TRG_COM_TIM14_Handler": { + "Prompt": "TIM8_TRG_COM_TIM14 Handler", + "Def": "USE_TIM8_TRG_COM_TIM14_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + } + } + }, + "ADC": { + "Defines": { + "ADC1_Enable": { + "Prompt": "ADC1 Enable", + "Def": "ADC1_ENABLE", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "ADC2_Enable": { + "Prompt": "ADC2 Enable", + "Def": "ADC2_ENABLE", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "Sample_Rate": { + "Prompt": "Sample Rate (Hz)", + "Def": "SAMPLE_RATE", + "Type": "edit", + "Default": 48000, + "NewRow": true + } + } + } +} \ No newline at end of file diff --git a/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h index 2690909..6ad9d73 100644 --- a/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h +++ b/MCU_STM32F1xx_Matlab/stm32f1xx_matlab_conf.h @@ -12,7 +12,7 @@ // DEFINES (UNCOMMENT WHAT YOU WILL SIMULATE) // TIMS //#define USE_TIM1 -#define USE_TIM2 +//#define USE_TIM2 //#define USE_TIM3 //#define USE_TIM4 //#define USE_TIM5 diff --git a/MCU_Wrapper/mexing.m b/MCU_Wrapper/mexing.m new file mode 100644 index 0000000..a3c2709 --- /dev/null +++ b/MCU_Wrapper/mexing.m @@ -0,0 +1,718 @@ +% Компилирует S-function +function mexing(compile_mode) + global Ts + Ts = 0.00001; + + if compile_mode == 1 + delete("*.mexw64") + delete("*.mexw64.pdb") + delete(".\MCU_Wrapper\Outputs\*.*"); + set_param(gcb, 'consoleOutput', ''); + % Дефайны + definesWrapperArg = buildWrapperDefinesString(); + definesUserArg = parseDefinesMaskText(); + definesConfigArg = buildConfigDefinesString(); + definesAllArg = [definesUserArg + " " + definesWrapperArg + " " + definesConfigArg]; + + %режимы компиляции + if read_checkbox('enableDebug') + modeArg = "debug"; + else + modeArg = "release"; + end + if read_checkbox('fullOutput') || read_checkbox('extConsol') + echoArg = 'echo_enable'; + else + echoArg = 'echo_disable'; + end + + [includesArg, codeArg] = make_mex_arguments('incTable', 'srcTable'); + + % Вызов батника с двумя параметрами: includes и code + cmd = sprintf('.\\MCU_Wrapper\\run_mex.bat "%s" "%s" "%s" %s %s', includesArg, codeArg, definesAllArg, modeArg, echoArg); + + if read_checkbox('extConsol') + cmdout = runBatAndShowOutput(cmd); + else + [status, cmdout]= system(cmd); + end + + % Сохраним вывод в параметр маски с именем 'consoleOutput' + set_param(gcb, 'consoleOutput', cmdout); + + beep + else + blockPath = bdroot; + config = read_periph_config(); + config = update_config_from_mask(blockPath, config); + write_periph_config(config); + update_mask_from_config(blockPath, config); + % set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters'); + end +end + +%% COMPILE PARAMS + + +function [includesArg, codeArg] = make_mex_arguments(incTableName, srcTableame) +%MAKE_MEX_ARGUMENTS Формирует строки аргументов для вызова mex-компиляции через батник +% +% [includesArg, codeArg] = make_mex_arguments(includesCell, codeCell) +% +% Вход: +% includesCell — ячейковый массив путей к директориям include +% codeCell — ячейковый массив исходных файлов +% +% Выход: +% includesArg — строка для передачи в батник, например: "-I"inc1" -I"inc2"" +% codeArg — строка с исходниками, например: ""src1.c" "src2.cpp"" + + + % Здесь пример получения из маски текущего блока (замени по своему) + blockHandle = gcbh; % или замени на нужный блок + + includesCell = parseCellString(get_param(blockHandle, incTableName)); + codeCell = parseCellString(get_param(blockHandle, srcTableame)); + + % Оборачиваем пути в кавычки и добавляем -I + includesStr = strjoin(cellfun(@(f) ['-I"' f '"'], includesCell, 'UniformOutput', false), ' '); + + % Оборачиваем имена файлов в кавычки + codeStr = strjoin(cellfun(@(f) ['"' f '"'], codeCell, 'UniformOutput', false), ' '); + + % Удаляем символ переноса строки и пробел в конце, если вдруг попал + codeStr = strtrim(codeStr); + includesStr = strtrim(includesStr); + + % Оборачиваем всю строку в кавычки, чтобы батник корректно понял + % includesArg = ['"' includesStr '"']; + % codeArg = ['"' codeStr '"']; + includesArg = includesStr; + codeArg = codeStr; + +end + + +function definesWrapperArg = buildWrapperDefinesString() + + definesWrapperArg = ''; + definesWrapperArg = addDefineByParam(definesWrapperArg, 'enableThreading', 0); + definesWrapperArg = addDefineByParam(definesWrapperArg, 'enableDeinit', 0); + definesWrapperArg = addDefineByParam(definesWrapperArg, 'threadCycles', 1); + definesWrapperArg = addDefineByParam(definesWrapperArg, 'mcuClk', 1); +end + + +function definesUserArg = parseDefinesMaskText() + blockHandle = gcbh; + % Получаем MaskValues и MaskNames + maskValues = get_param(blockHandle, 'MaskValues'); + paramNames = get_param(blockHandle, 'MaskNames'); + + % Индекс параметра userDefs + idxUserDefs = find(strcmp(paramNames, 'userDefs')); + definesText = maskValues{idxUserDefs}; % Текст с пользовательскими определениями + + % Убираем буквальные символы \n и \r + definesText = strrep(definesText, '\n', ' '); + definesText = strrep(definesText, '\r', ' '); + + % Разбиваем по переносам строк + lines = split(definesText, {'\n', '\r\n', '\r'}); + + parts = strings(1,0); % пустой массив строк + + for k = 1:numel(lines) + line = strtrim(lines{k}); + if isempty(line) + continue; + end + + % Разбиваем по пробелам, чтобы получить отдельные определения в строке + tokens = split(line); + + for t = 1:numel(tokens) + token = strtrim(tokens{t}); + if isempty(token) + continue; + end + + eqIdx = strfind(token, '='); + if isempty(eqIdx) + % Просто ключ без значения + parts(end+1) = sprintf('-D"%s"', token); + else + key = strtrim(token(1:eqIdx(1)-1)); + val = strtrim(token(eqIdx(1)+1:end)); + parts(end+1) = sprintf('-D"%s__EQ__%s"', key, val); + end + end + end + + definesUserArg = strjoin(parts, ' '); +end + + + +function definesWrapperArg = buildConfigDefinesString() + blockHandle = gcbh; + mask = Simulink.Mask.get(blockHandle); + + tabName = 'configTab'; % Имя вкладки (Prompt) + + allControls = mask.getDialogControls(); + tabCtrl = find_tab_by_name(allControls, tabName); + + if isempty(tabCtrl) + error('Вкладка с названием "%s" не найдена в маске', tabName); + end + definesWrapperArg = ''; + % Получаем все контролы внутри вкладки + children = tabCtrl.DialogControls; + for i = 1:numel(children) + ctrl = children(i); + % Получаем имя параметра из контрола + paramName = ctrl.Name; + try + % Получаем объект параметра по имени + param = mask.getParameter(paramName); + + % Определяем тип параметра + switch lower(param.Type) + case 'checkbox' + definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0); + case 'edit' + definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1); + otherwise + % Необрабатываемые типы + end + catch ME + warning('Не удалось получить параметр "%s": %s', paramName, ME.message); + end + end +end + + +%% PARSE FUNCTIONS + +function out = parseCellString(str) + str = strtrim(str); + if startsWith(str, '{') && endsWith(str, '}') + str = str(2:end-1); + end + + parts = split(str, ';'); + out = cell(numel(parts), 1); + for i = 1:numel(parts) + el = strtrim(parts{i}); + if startsWith(el, '''') && endsWith(el, '''') + el = el(2:end-1); + end + out{i} = el; + end + + if isempty(out) || (numel(out) == 1 && isempty(out{1})) + out = {}; + end +end + +function str = cellArrayToString(cellArray) + quoted = cellfun(@(s) ['''' s ''''], cellArray, 'UniformOutput', false); + str = ['{' strjoin(quoted, ';') '}']; +end + + +function definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, val_define) + blockHandle = gcbh; + mask = Simulink.Mask.get(blockHandle); + + % Получаем MaskValues, MaskNames + maskValues = get_param(blockHandle, 'MaskValues'); + paramNames = get_param(blockHandle, 'MaskNames'); + param = mask.getParameter(paramName); % для alias + + % Найдём индекс нужного параметра + idxParam = find(strcmp(paramNames, paramName), 1); + if isempty(idxParam) + error('Parameter "%s" not found in block mask parameters.', paramName); + end + + % Берём alias из маски + alias = param.Alias; + + if val_define ~= 0 + % Значение параметра + val = maskValues{idxParam}; + % Формируем define с кавычками и значением + newDefine = ['-D"' alias '__EQ__' val '"']; + else + if read_checkbox(paramName) + % Формируем define с кавычками без значения + newDefine = ['-D"' alias '"']; + else + newDefine = ''; + end + end + + + + % Добавляем новый define к существующему (string) + if isempty(definesWrapperArg) || strlength(strtrim(definesWrapperArg)) == 0 + definesWrapperArg = newDefine; + else + definesWrapperArg = definesWrapperArg + " " + newDefine; + end +end + + + +function checkbox_state = read_checkbox(checkboxName) + maskValues = get_param(gcbh, 'MaskValues'); + paramNames = get_param(gcbh, 'MaskNames'); + + inxCheckBox = find(strcmp(paramNames, checkboxName)); + + checkbox_state_str = maskValues{inxCheckBox}; + if strcmpi(checkbox_state_str, 'on') + checkbox_state = 1; + else + checkbox_state = 0; + end +end + +%% CONSOLE FUNCTIONS + +function cmdret = runBatAndShowOutput(cmd) + import java.io.*; + import java.lang.*; + cmdEnglish = ['chcp 437 > nul && ' cmd]; + pb = java.lang.ProcessBuilder({'cmd.exe', '/c', cmdEnglish}); + pb.redirectErrorStream(true); + process = pb.start(); + + reader = BufferedReader(InputStreamReader(process.getInputStream())); + + cmdret = ""; % Здесь будем накапливать весь вывод + + while true + if reader.ready() + line = char(reader.readLine()); + if isempty(line) + break; + end + cmdret = cmdret + string(line) + newline; % сохраняем вывод + % Здесь выводим только новую строку + safeLine = strrep(line, '''', ''''''); % Экранируем апострофы + logWindow_append(safeLine); + drawnow; % обновляем GUI + else + if ~process.isAlive() + % дочитываем оставшиеся строки + while reader.ready() + line = char(reader.readLine()); + if isempty(line) + break; + end + cmdret = cmdret + string(line) + newline; % сохраняем вывод + safeLine = strrep(line, '''', ''''''); + logWindow_append(safeLine); + drawnow; + end + break; + end + pause(0.2); + end + end + process.waitFor(); +end + + +function logWindow_append(line) + persistent fig hEdit jScrollPane jTextArea + + if isempty(fig) || ~isvalid(fig) + fig = figure('Name', 'Log Window', 'Position', [100 100 600 400]); + hEdit = uicontrol('Style', 'edit', ... + 'Max', 2, 'Min', 0, ... + 'Enable', 'on', ... + 'FontName', 'Courier New', ... + 'Position', [10 10 580 380], ... + 'HorizontalAlignment', 'left', ... + 'BackgroundColor', 'white', ... + 'Tag', 'LogWindowFigure'); + + jScrollPane = findjobj(hEdit); % JScrollPane + jTextArea = jScrollPane.getViewport.getView; % JTextArea внутри JScrollPane + end + + oldText = get(hEdit, 'String'); + if ischar(oldText) + oldText = {oldText}; + end + + set(hEdit, 'String', [oldText; {line}]); + drawnow; + % Автоскролл вниз: + jTextArea.setCaretPosition(jTextArea.getDocument.getLength); + drawnow; +end + + +%% READ CONFIGS +function config = read_periph_config() + jsonText = fileread('periph_config.json'); + config = jsondecode(jsonText); +end + +function write_periph_config(config) + jsonText = jsonencode(config, 'PrettyPrint', true); + fid = fopen('periph_config.json', 'w'); + if fid == -1 + error('Не удалось открыть файл periph_config.json для записи.'); + end + fwrite(fid, jsonText, 'char'); + fclose(fid); +end + +%% CONFIG MASK TOOLS +function update_mask_from_config(blockPath, config) + blockPath = [blockPath '/MCU']; + + % Проверяем, была ли маска открыта + wasOpen = isMaskDialogOpen(blockPath); + close_system(blockPath, 0); + mask = Simulink.Mask.get(blockPath); + + tableNames = {'incTable', 'srcTable'}; + columns_backup = clear_tables(blockPath, tableNames); + + containerName = 'configTabAll'; + clear_all_from_container(mask, containerName); + + % Ищем контейнер, в который будем добавлять вкладки + allControls = mask.getDialogControls(); + container = find_container_by_name(allControls, containerName); + if isempty(container) + error('Контейнер "%s" не найден в маске.', containerName); + end + + % Проходим по каждому модулю (ADC, TIM...) + periphs = fieldnames(config); + for i = 1:numel(periphs) + periph = periphs{i}; + defines = config.(periph).Defines; + defNames = fieldnames(defines); + + % Создаём вкладку для модуля + tabCtrl = container.addDialogControl('tab', periph); + tabCtrl.Prompt = [periph ' Config']; + + for j = 1:numel(defNames) + defPrompt = defNames{j}; + def = defines.(defPrompt); + prompt = def.Prompt; + + % Только checkbox и edit + switch lower(def.Type) + case 'checkbox' + paramType = 'checkbox'; + case 'edit' + paramType = 'edit'; + otherwise + continue; + end + + paramName = matlab.lang.makeValidName(defPrompt); + + % Преобразуем значение по типу + val = def.Default; + if islogical(val) + if val + valStr = 'on'; + else + valStr = 'off'; + end + elseif isnumeric(val) + valStr = num2str(val); + elseif ischar(val) + valStr = val; + else + error('Unsupported default value type for %s.%s', periph, defPrompt); + end + + % Добавляем параметр в соответствующую вкладку + param = mask.addParameter( ... + 'Type', paramType, ... + 'Prompt', prompt, ... + 'Name', paramName, ... + 'Value', valStr, ... + 'Container', periph ... + ); + + param.Alias = def.Def; + if def.NewRow + row_param = 'new'; + else + row_param = 'current'; + end + param.DialogControl.Row = row_param; + end + end + + % Восстанавливаем таблицы + restore_tables(blockPath, tableNames, columns_backup); + + % Повторно открываем маску, если она была открыта + if wasOpen + open_system(blockPath, 'mask'); + end +end + +function config = update_config_from_mask(blockPath, config) + blockPath = [blockPath '/MCU']; + mask = Simulink.Mask.get(blockPath); + + periphs = fieldnames(config); + + for i = 1:numel(periphs) + periph = periphs{i}; + defines = config.(periph).Defines; + defNames = fieldnames(defines); + + for j = 1:numel(defNames) + defPrompt = defNames{j}; + paramName = matlab.lang.makeValidName(defPrompt); + param = mask.getParameter(paramName); + + % Получаем значение из маски и сохраняем в конфиг + valStr = param.Value; + + % Преобразуем строку в соответствующий тип + if strcmpi(defines.(defPrompt).Type, 'checkbox') + config.(periph).Defines.(defPrompt).Default = strcmpi(valStr, 'on'); + elseif strcmpi(defines.(defPrompt).Type, 'edit') + valNum = str2double(valStr); + if isnan(valNum) + config.(periph).Defines.(defPrompt).Default = valStr; + else + config.(periph).Defines.(defPrompt).Default = valNum; + end + end + end + end +end + + +function clear_all_from_container(mask, containerName) + allControls = mask.getDialogControls(); + container = find_container_by_name(allControls, containerName); + if isempty(container) + warning('Контейнер "%s" не найден.', containerName); + return; + end + + % Рекурсивно собрать все параметры (не вкладки) + paramsToDelete = collect_all_parameters(container); + + % Удаляем все параметры + for i = 1:numel(paramsToDelete) + try + mask.removeParameter(paramsToDelete{i}); + catch + warning('Не удалось удалить параметр %s', paramsToDelete{i}); + end + end + + % Рекурсивно удалить все вкладки внутри контейнера + delete_all_tabs(mask, container); +end + +function params = collect_all_parameters(container) + params = {}; + children = container.DialogControls; + for i = 1:numel(children) + ctrl = children(i); + if isa(ctrl, 'Simulink.dialog.Tab') + % Если вкладка — рекурсивно собираем параметры внутри неё + params = [params, collect_all_parameters(ctrl)]; + else + % Иначе это параметр — добавляем имя + params{end+1} = ctrl.Name; %#ok + end + end +end + + + +function delete_all_tabs(mask, container) + children = container.DialogControls; + % Идём в обратном порядке, чтобы безопасно удалять + for i = numel(children):-1:1 + ctrl = children(i); + if isa(ctrl, 'Simulink.dialog.Tab') + % Сначала рекурсивно удаляем вкладки внутри текущей вкладки + delete_all_tabs(mask, ctrl); + try + container.removeDialogControl(ctrl.Name); + catch ME + warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message); + end + end + end +end + + +function isOpen = isMaskDialogOpen(blockPath) + isOpen = false; + + try + % Получаем имя блока + blockName = get_param(blockPath, 'Name'); + + % Получаем список окон MATLAB GUI + jWindows = java.awt.Window.getWindows(); + + for i = 1:numel(jWindows) + win = jWindows(i); + + % Проверка, что окно видимое и активно + if win.isShowing() + try + title = char(win.getTitle()); + % Проверка по ключевому слову, соответствующему заголовку маски + if contains(title, ['Mask Editor: ' blockName]) || ... + contains(title, ['Mask: ' blockName]) || ... + contains(title, blockName) + isOpen = true; + return; + end + catch + % Окно не имеет заголовка — пропускаем + end + end + end + catch + isOpen = false; + end +end + + + +function column_titles = clear_tables(block, table_names) + % Очищает столбцы в каждой таблице из массива имен table_names + % Возвращает cell-массив с названиями первых столбцов каждой таблицы + + % Получить объект маски блока + maskObj = Simulink.Mask.get(block); + + % Инициализировать cell-массив для хранения названий столбцов + column_titles = cell(size(table_names)); + + for k = 1:numel(table_names) + table_name = table_names{k}; + + % Получить объект управления таблицей + tableControl = maskObj.getDialogControl(table_name); + + % Получить количество столбцов + nCols = tableControl.getNumberOfColumns; + + if nCols > 0 + % Получить первый столбец (который будем удалять) + column = tableControl.getColumn(1); + column_titles{k} = column.Name; + + % Удаляем все столбцы + % Важно: при удалении столбцов индексы меняются, + % поэтому удаляем всегда первый столбец nCols раз + for i = 1:nCols + tableControl.removeColumn(1); + end + else + % Если столбцов нет, возвращаем пустую строку + column_titles{k} = ''; + end + end +end + +function restore_tables(block, table_names, column_titles) + % Восстанавливает первый столбец в каждой таблице из массива имен + % Использует массив column_titles для установки имени столбца + + % Получить объект маски блока + maskObj = Simulink.Mask.get(block); + + for k = 1:numel(table_names) + table_name = table_names{k}; + title = column_titles{k}; + + % Получить объект управления таблицей + tableControl = maskObj.getDialogControl(table_name); + + % Добавить новый столбец + column = tableControl.addColumn(Name='title', Type='edit'); + column.Name = title; + end +end + + + + +function tab = find_tab_by_name(controls, targetName) + tab = []; + + for i = 1:numel(controls) + ctrl = controls(i); + + % Проверяем, вкладка ли это и совпадает ли имя + if isa(ctrl, 'Simulink.dialog.Tab') && strcmp(ctrl.Name, targetName) + tab = ctrl; + return; + end + + % Если это контейнер — обходим его детей + children = get_children(ctrl); + if ~isempty(children) + tab = find_tab_by_name(children, targetName); + if ~isempty(tab) + return; + end + end + end +end + +function container = find_container_by_name(controls, targetName) + container = []; + + for i = 1:numel(controls) + ctrl = controls(i); + + % Проверяем, контейнер ли это и совпадает ли имя + if isa(ctrl, 'Simulink.dialog.Container') && strcmp(ctrl.Name, targetName) + container = ctrl; + return; + end + + % Если это вложенный контрол — обходим его детей + children = get_children(ctrl); + if ~isempty(children) + container = find_container_by_name(children, targetName); + if ~isempty(container) + return; + end + end + end +end + + +function children = get_children(ctrl) + if isprop(ctrl, 'DialogControls') + children = ctrl.DialogControls; + elseif isprop(ctrl, 'Controls') + children = ctrl.Controls; + elseif isprop(ctrl, 'Children') + children = ctrl.Children; + else + children = []; + end +end diff --git a/mcu_test_r2023.slx b/mcu_test_r2023.slx index 07ba88c..68dd38e 100644 Binary files a/mcu_test_r2023.slx and b/mcu_test_r2023.slx differ diff --git a/mexing.asv b/mexing.asv index 384b703..9284b7b 100644 --- a/mexing.asv +++ b/mexing.asv @@ -43,7 +43,9 @@ function mexing(compile_mode) beep else blockPath = bdroot; - config = load_periph_config(); + config = read_periph_config(); + config = update_config_from_mask(blockPath, config); + write_periph_config(config); update_mask_from_config(blockPath, config); % set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters'); end @@ -156,15 +158,19 @@ function definesWrapperArg = buildConfigDefinesString() blockHandle = gcbh; mask = Simulink.Mask.get(blockHandle); - tabName = 'configTab'; % Имя вкладки (Prompt) + tabName = 'configTabAll'; % Имя вкладки (Prompt) allControls = mask.getDialogControls(); - tabCtrl = find_tab_by_name(allControls, tabName); + tabCtrl = find_container_by_name(allControls, tabName); if isempty(tabCtrl) error('Вкладка с названием "%s" не найдена в маске', tabName); end + + collect_all_parameters + definesWrapperArg = ''; + % Получаем все контролы внутри вкладки children = tabCtrl.DialogControls; for i = 1:numel(children) @@ -185,7 +191,7 @@ function definesWrapperArg = buildConfigDefinesString() % Необрабатываемые типы end catch ME - warning('Не удалось получить параметр "%s": %s', paramName, ME.message); + % warning('Не удалось получить параметр "%s": %s', paramName, ME.message); end end end @@ -357,11 +363,33 @@ end %% READ CONFIGS -function config = load_periph_config() - jsonText = fileread('periph_config.json'); +function config = read_periph_config() + blockHandle = gcbh; + mask = Simulink.Mask.get(blockHandle); + + pathparam = mask.getParameter('periphPath'); + config_path = pathparam.Value; + + jsonText = fileread(config_path); config = jsondecode(jsonText); end +function write_periph_config(config) + blockHandle = gcbh; + mask = Simulink.Mask.get(blockHandle); + + pathparam = mask.getParameter('periphPath'); + config_path = pathparam.Value; + + jsonText = jsonencode(config, 'PrettyPrint', true); + fid = fopen(config_path, 'w'); + if fid == -1 + error('Не удалось открыть файл periph_config.json для записи.'); + end + fwrite(fid, jsonText, 'char'); + fclose(fid); +end + %% CONFIG MASK TOOLS function update_mask_from_config(blockPath, config) blockPath = [blockPath '/MCU']; @@ -392,16 +420,13 @@ function update_mask_from_config(blockPath, config) defNames = fieldnames(defines); % Создаём вкладку для модуля - tabCtrl = mask.addDialogControl( ... - 'Type', 'Tab', ... - 'Prompt', periph, ... - 'Name', [periph '_Tab'], ... - 'Container', containerName ... - ); + tabCtrl = container.addDialogControl('tab', periph); + tabCtrl.Prompt = [periph ' Config']; for j = 1:numel(defNames) defPrompt = defNames{j}; def = defines.(defPrompt); + prompt = def.Prompt; % Только checkbox и edit switch lower(def.Type) @@ -418,7 +443,11 @@ function update_mask_from_config(blockPath, config) % Преобразуем значение по типу val = def.Default; if islogical(val) - valStr = logical(val) * "on" + ~val * "off"; + if val + valStr = 'on'; + else + valStr = 'off'; + end elseif isnumeric(val) valStr = num2str(val); elseif ischar(val) @@ -428,16 +457,21 @@ function update_mask_from_config(blockPath, config) end % Добавляем параметр в соответствующую вкладку - mask.addParameter( ... + param = mask.addParameter( ... 'Type', paramType, ... - 'Prompt', defPrompt, ... + 'Prompt', prompt, ... 'Name', paramName, ... 'Value', valStr, ... 'Container', periph ... ); - param = mask.getParameter(paramName); param.Alias = def.Def; + if def.NewRow + row_param = 'new'; + else + row_param = 'current'; + end + param.DialogControl.Row = row_param; end end @@ -450,31 +484,94 @@ function update_mask_from_config(blockPath, config) end end +function config = update_config_from_mask(blockPath, config) + blockPath = [blockPath '/MCU']; + mask = Simulink.Mask.get(blockPath); + + periphs = fieldnames(config); + + for i = 1:numel(periphs) + periph = periphs{i}; + defines = config.(periph).Defines; + defNames = fieldnames(defines); + + for j = 1:numel(defNames) + defPrompt = defNames{j}; + paramName = matlab.lang.makeValidName(defPrompt); + param = mask.getParameter(paramName); + + % Получаем значение из маски и сохраняем в конфиг + valStr = param.Value; + + % Преобразуем строку в соответствующий тип + if strcmpi(defines.(defPrompt).Type, 'checkbox') + config.(periph).Defines.(defPrompt).Default = strcmpi(valStr, 'on'); + elseif strcmpi(defines.(defPrompt).Type, 'edit') + valNum = str2double(valStr); + if isnan(valNum) + config.(periph).Defines.(defPrompt).Default = valStr; + else + config.(periph).Defines.(defPrompt).Default = valNum; + end + end + end + end +end function clear_all_from_container(mask, containerName) -% Очищает все параметры и вкладки внутри указанного контейнера - allControls = mask.getDialogControls(); container = find_container_by_name(allControls, containerName); - if isempty(container) - error('Контейнер с именем "%s" не найден.', containerName); + warning('Контейнер "%s" не найден.', containerName); + return; end - children = container.DialogControls; + % Рекурсивно собрать все параметры (не вкладки) + paramsToDelete = collect_all_parameters(container); + % Удаляем все параметры + for i = 1:numel(paramsToDelete) + try + mask.removeParameter(paramsToDelete{i}); + catch + warning('Не удалось удалить параметр %s', paramsToDelete{i}); + end + end + + % Рекурсивно удалить все вкладки внутри контейнера + delete_all_tabs(mask, container); +end + +function params = collect_all_parameters(container) + params = {}; + children = container.DialogControls; + for i = 1:numel(children) + ctrl = children(i); + if isa(ctrl, 'Simulink.dialog.Tab') + % Если вкладка — рекурсивно собираем параметры внутри неё + params = [params, collect_all_parameters(ctrl)]; + else + % Иначе это параметр — добавляем имя + params{end+1} = ctrl.Name; %#ok + end + end +end + + + +function delete_all_tabs(mask, container) + children = container.DialogControls; + % Идём в обратном порядке, чтобы безопасно удалять for i = numel(children):-1:1 ctrl = children(i); - try - % Пытаемся удалить как контрол (вкладка, контейнер и пр.) - mask.removeDialogControl(ctrl.Name); - catch + if isa(ctrl, 'Simulink.dialog.Tab') + % Сначала рекурсивно удаляем вкладки внутри текущей вкладки + delete_all_tabs(mask, ctrl); try - % Если не получилось — пробуем как параметр - res = mask.removeParameter(ctrl.Name); - catch - warning('Не удалось удалить "%s".', ctrl.Name); + container.removeDialogControl(ctrl.Name); + catch ME + warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message); end end end diff --git a/mexing.m b/mexing.m index 3be5e77..0188a9d 100644 --- a/mexing.m +++ b/mexing.m @@ -43,7 +43,9 @@ function mexing(compile_mode) beep else blockPath = bdroot; - config = load_periph_config(); + config = read_periph_config(); + config = update_config_from_mask(blockPath, config); + write_periph_config(config); update_mask_from_config(blockPath, config); % set_param(gcb, 'consoleOutput', 'Peripheral configuration file loaded. Re-open Block Parameters'); end @@ -156,37 +158,37 @@ function definesWrapperArg = buildConfigDefinesString() blockHandle = gcbh; mask = Simulink.Mask.get(blockHandle); - tabName = 'configTab'; % Имя вкладки (Prompt) + tabName = 'configTabAll'; % Имя вкладки (Prompt) allControls = mask.getDialogControls(); - tabCtrl = find_tab_by_name(allControls, tabName); + tabCtrl = find_container_by_name(allControls, tabName); if isempty(tabCtrl) error('Вкладка с названием "%s" не найдена в маске', tabName); end + + + params = collect_all_parameters(tabCtrl); definesWrapperArg = ''; - % Получаем все контролы внутри вкладки - children = tabCtrl.DialogControls; - for i = 1:numel(children) - ctrl = children(i); + for i = 1:numel(params) % Получаем имя параметра из контрола - paramName = ctrl.Name; - try - % Получаем объект параметра по имени - param = mask.getParameter(paramName); - - % Определяем тип параметра - switch lower(param.Type) - case 'checkbox' - definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0); - case 'edit' - definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1); - otherwise - % Необрабатываемые типы - end - catch ME - warning('Не удалось получить параметр "%s": %s', paramName, ME.message); + paramName = string(params(i)); + try + % Получаем объект параметра по имени + param = mask.getParameter(paramName); + + % Определяем тип параметра + switch lower(param.Type) + case 'checkbox' + definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 0); + case 'edit' + definesWrapperArg = addDefineByParam(definesWrapperArg, paramName, 1); + otherwise + % Необрабатываемые типы end + catch ME + % warning('Не удалось получить параметр "%s": %s', paramName, ME.message); + end end end @@ -357,11 +359,33 @@ end %% READ CONFIGS -function config = load_periph_config() - jsonText = fileread('periph_config.json'); +function config = read_periph_config() + blockHandle = gcbh; + mask = Simulink.Mask.get(blockHandle); + + pathparam = mask.getParameter('periphPath'); + config_path = pathparam.Value; + + jsonText = fileread(config_path); config = jsondecode(jsonText); end +function write_periph_config(config) + blockHandle = gcbh; + mask = Simulink.Mask.get(blockHandle); + + pathparam = mask.getParameter('periphPath'); + config_path = pathparam.Value; + + jsonText = jsonencode(config, 'PrettyPrint', true); + fid = fopen(config_path, 'w'); + if fid == -1 + error('Не удалось открыть файл periph_config.json для записи.'); + end + fwrite(fid, jsonText, 'char'); + fclose(fid); +end + %% CONFIG MASK TOOLS function update_mask_from_config(blockPath, config) blockPath = [blockPath '/MCU']; @@ -392,16 +416,13 @@ function update_mask_from_config(blockPath, config) defNames = fieldnames(defines); % Создаём вкладку для модуля - tabCtrl = mask.addDialogControl( ... - 'Type', 'Tab', ... - 'Prompt', periph, ... - 'Name', [periph '_Tab'], ... - 'Container', containerName ... - ); + tabCtrl = container.addDialogControl('tab', periph); + tabCtrl.Prompt = [periph ' Config']; for j = 1:numel(defNames) defPrompt = defNames{j}; def = defines.(defPrompt); + prompt = def.Prompt; % Только checkbox и edit switch lower(def.Type) @@ -418,7 +439,11 @@ function update_mask_from_config(blockPath, config) % Преобразуем значение по типу val = def.Default; if islogical(val) - valStr = logical(val) * "on" + ~val * "off"; + if val + valStr = 'on'; + else + valStr = 'off'; + end elseif isnumeric(val) valStr = num2str(val); elseif ischar(val) @@ -428,16 +453,21 @@ function update_mask_from_config(blockPath, config) end % Добавляем параметр в соответствующую вкладку - mask.addParameter( ... + param = mask.addParameter( ... 'Type', paramType, ... - 'Prompt', defPrompt, ... + 'Prompt', prompt, ... 'Name', paramName, ... 'Value', valStr, ... 'Container', periph ... ); - param = mask.getParameter(paramName); param.Alias = def.Def; + if def.NewRow + row_param = 'new'; + else + row_param = 'current'; + end + param.DialogControl.Row = row_param; end end @@ -450,6 +480,49 @@ function update_mask_from_config(blockPath, config) end end +function config = update_config_from_mask(blockPath, config) + blockPath = [blockPath '/MCU']; + mask = Simulink.Mask.get(blockPath); + maskParams = mask.Parameters; + paramNames = arrayfun(@(p) p.Name, maskParams, 'UniformOutput', false); + + periphs = fieldnames(config); + + for i = 1:numel(periphs) + periph = periphs{i}; + defines = config.(periph).Defines; + defNames = fieldnames(defines); + + for j = 1:numel(defNames) + defPrompt = defNames{j}; + paramName = matlab.lang.makeValidName(defPrompt); + + % Проверка, существует ли параметр с таким именем + if ismember(paramName, paramNames) + param = mask.getParameter(paramName); + % Получаем значение из маски и сохраняем в конфиг + valStr = param.Value; + + % Проверяем, существует ли элемент defPrompt в структуре defines + if isfield(defines, defPrompt) + % Преобразуем строку в соответствующий тип + if strcmpi(defines.(defPrompt).Type, 'checkbox') + config.(periph).Defines.(defPrompt).Default = strcmpi(valStr, 'on'); + elseif strcmpi(defines.(defPrompt).Type, 'edit') + valNum = str2double(valStr); + if isnan(valNum) + config.(periph).Defines.(defPrompt).Default = valStr; + else + config.(periph).Defines.(defPrompt).Default = valNum; + end + end + end + end + end + end +end + + function clear_all_from_container(mask, containerName) allControls = mask.getDialogControls(); container = find_container_by_name(allControls, containerName); @@ -489,18 +562,20 @@ function params = collect_all_parameters(container) end end + + function delete_all_tabs(mask, container) children = container.DialogControls; % Идём в обратном порядке, чтобы безопасно удалять for i = numel(children):-1:1 ctrl = children(i); if isa(ctrl, 'Simulink.dialog.Tab') - % Рекурсивно удаляем вкладки внутри текущей вкладки + % Сначала рекурсивно удаляем вкладки внутри текущей вкладки delete_all_tabs(mask, ctrl); try - mask.removeParameter(ctrl.Name); - catch - warning('Не удалось удалить вкладку %s', ctrl.Name); + container.removeDialogControl(ctrl.Name); + catch ME + warning('Не удалось удалить вкладку %s: %s', ctrl.Name, ME.message); end end end diff --git a/periph_config.json b/periph_config.json index 379ebce..768cae8 100644 --- a/periph_config.json +++ b/periph_config.json @@ -1,40 +1,252 @@ { - "ADC": { + "RCC": { "Defines": { - "ADC1 Enable": { - "Def": "ADC1_ENABLE", - "Type": "checkbox", - "Default": true - }, - "ADC2 Enable": { - "Def": "ADC2_ENABLE", - "Type": "checkbox", - "Default": true - }, - "Sample Rate (Hz)": { - "Def": "SAMPLE_RATE", + "HCLK_Clock": { + "Prompt": "HCLK Clock (Hz)", + "Def": "HCLK_Value", "Type": "edit", - "Default": 48000 + "Default": 7.2E+7, + "NewRow": true + }, + "ABP1_Clock": { + "Prompt": "ABP1 Clock (Hz)", + "Def": "ABP1_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP1_TIMS_Clock": { + "Prompt": "ABP1 Tim's Clock (Hz)", + "Def": "ABP1_TIMS_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP2_Clock": { + "Prompt": "ABP2 Clock (Hz)", + "Def": "ABP2_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true + }, + "ABP2_TIMS_Clock": { + "Prompt": "ABP2 Tim's Clock (Hz)", + "Def": "ABP2_TIMS_Value", + "Type": "edit", + "Default": 7.2E+7, + "NewRow": true } } }, "TIM": { "Defines": { - "TIM1 Enable": { - "Def": "TIM1_ENABLE", + "TIM1_Enable": { + "Prompt": "TIM1 Enable", + "Def": "USE_TIM1", "Type": "checkbox", - "Default": true + "Default": false, + "NewRow": true }, - "TIM2 Enable": { - "Def": "TIM2_ENABLE", + "TIM1_UP_TIM10_Handler": { + "Prompt": "TIM1_UP_TIM10 Handler", + "Def": "USE_TIM1_UP_TIM10_HANDLER", "Type": "checkbox", - "Default": true + "Default": false, + "NewRow": false }, - "AHB Buf Clock Rate (MHz)": { - "Def": "AHB_BUS_FREQ", - "Type": "edit", - "Default": 72 + "TIM2_Enable": { + "Prompt": "TIM2 Enable", + "Def": "USE_TIM2", + "Type": "checkbox", + "Default": true, + "NewRow": true + }, + "TIM2_Handler": { + "Prompt": "TIM2 Handler", + "Def": "USE_TIM2_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM3_Enable": { + "Prompt": "TIM3 Enable", + "Def": "USE_TIM3", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM3_Handler": { + "Prompt": "TIM3 Handler", + "Def": "USE_TIM3_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM4_Enable": { + "Prompt": "TIM4 Enable", + "Def": "USE_TIM4", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM4_Handler": { + "Prompt": "TIM4 Handler", + "Def": "USE_TIM4_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM5_Enable": { + "Prompt": "TIM5 Enable", + "Def": "USE_TIM5", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM5_Handler": { + "Prompt": "TIM5 Handler", + "Def": "USE_TIM5_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM6_Enable": { + "Prompt": "TIM6 Enable", + "Def": "USE_TIM6", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM6_Handler": { + "Prompt": "TIM6 Handler", + "Def": "USE_TIM6_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM7_Enable": { + "Prompt": "TIM7 Enable", + "Def": "USE_TIM7", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM7_Handler": { + "Prompt": "TIM7 Handler", + "Def": "USE_TIM7_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM8_Enable": { + "Prompt": "TIM8 Enable", + "Def": "USE_TIM8", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM8_UP_TIM13_Handler": { + "Prompt": "TIM8_UP_TIM13 Handler", + "Def": "USE_TIM8_UP_TIM13_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM9_Enable": { + "Prompt": "TIM9 Enable", + "Def": "USE_TIM9", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM1_BRK_TIM9_Handler": { + "Prompt": "TIM1_BRK_TIM9 Handler", + "Def": "USE_TIM1_BRK_TIM9_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM10_Enable": { + "Prompt": "TIM10 Enable", + "Def": "USE_TIM10", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM11_Enable": { + "Prompt": "TIM11 Enable", + "Def": "USE_TIM11", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM1_TRG_COM_TIM11_Handler": { + "Prompt": "TIM1_TRG_COM_TIM11 Handler", + "Def": "USE_TIM1_TRG_COM_TIM11_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM12_Enable": { + "Prompt": "TIM12 Enable", + "Def": "USE_TIM12", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM8_BRK_TIM12_Handler": { + "Prompt": "TIM8_BRK_TIM12 Handler", + "Def": "USE_TIM8_BRK_TIM12_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false + }, + "TIM13_Enable": { + "Prompt": "TIM13 Enable", + "Def": "USE_TIM13", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM14_Enable": { + "Prompt": "TIM14 Enable", + "Def": "USE_TIM14", + "Type": "checkbox", + "Default": false, + "NewRow": true + }, + "TIM8_TRG_COM_TIM14_Handler": { + "Prompt": "TIM8_TRG_COM_TIM14 Handler", + "Def": "USE_TIM8_TRG_COM_TIM14_HANDLER", + "Type": "checkbox", + "Default": false, + "NewRow": false } } } -} + "ADC": { + "Defines": { + "ADC1_Enable": { + "Prompt": "ADC1 Enable", + "Def": "ADC1_ENABLE", + "Type": "checkbox", + "Default": true, + "NewRow": true + }, + "ADC2_Enable": { + "Prompt": "ADC2 Enable", + "Def": "ADC2_ENABLE", + "Type": "checkbox", + "Default": true, + "NewRow": true + }, + "Sample_Rate": { + "Prompt": "Sample Rate (Hz)", + "Def": "SAMPLE_RATE", + "Type": "edit", + "Default": 48000, + "NewRow": true + } + } + }, +} \ No newline at end of file