SinTableLoad macro Angle_8,PDC_16L ; Выборка из таблицы и засылка в PWM local ExitMul,Done,ZeroPoint, MaxPoint,Reverse,DoneAdress local OvrLoad,OvrLoad1,TopWithoutCharge,BotWithoutPWM ; Повторяющийся код оформлен макросом. ; На входе - адрес угла, на выходе - засылаем в ШИМ указанного № ; Внутри - максимально оптимизированный код выборки таблицы синусов, умножения на амплитуду, ; нормализации до необходимого значение для PCPWM, вывода в модулятор. ; Выполняется 24 414*3 = 73 242 Гц - каждая команда дорога. #ifdef PCPWM_12b ; 12 бит вычисления вместо 8 бит - пробуем на скорость swapf Angle_8-1,W,BANKED ; Младший нибл стал младшим в Акб andlw 0x0F ; чистим старший нибл Акб movwf TBLPTRL,ACCESS ; Буферизуем результат младшего нибла swapf Angle_8+0,W,BANKED ; Старший байт адреса с поменянными ниблами в Акб andlw 0xF0 ; чистим младший нибл Акб iorwf TBLPTRL,F,ACCESS ; Средний нибл в младшем байте указателя swapf Angle_8+0,W,BANKED ; Старший байт адреса с поменянными ниблами в Акб andlw 0x0F ; чистим старший нибл Акб movwf TBLPTRH,ACCESS ; Старший нибл в старшем байте указателя. ;; Итого 12 бит в указателе - 9 команд с пересылкой в указатель таблицы. ; Но длинна таблицы 11 бит значений - младший бит всегда фиксирован bcf TBLPTRL,0,ACCESS ; Таблица синусов - двух байтные числа ; 29/12/2019 если освободить 2 кб из под таблиц простых чисел то можно 2 таблицы синусов иметь с переклюком ; от угла между фазами - чистый косинус и косинус + 17% 3 гармоники. ; 19/01/2020 начал обдумывать реализацию использования 1/4 периода синуса. ; 12 бит адреса = знак вычитать/прибавлять к середине диапазона, ; 11 бит адреса - вперёд с начала/назад с конца считать таблицу (реализовано) #ifdef PCPWM_CoSinus; Yes ; Экономия ~2 Кб ПЗУ ценой усложнения фазного вычислителя на ~10 циклов ; ***** Попытка укоротить таблицу вдвое btfsc TBLPTRH,3,ACCESS ; Старший бит 12 бит угла bra Reverse ; Вычитаем #endif ; Add16L TBLPTRL,ACCESS,Table_Sinus ; Начальный адрес таблицы синусов #ifdef PCPWM_CoSinus; Yes ; Экономия ~2 Кб ПЗУ ценой усложнения фазного вычислителя на ~10 циклов bra DoneAdress Reverse ; Обратное движение с другого конца половины.синусоиды bcf TBLPTRH,3,ACCESS ; Старший бит 12 бит угла movf TBLPTRL,W,ACCESS ; sublw low(Table_Sinus+0x800) ; Из Конца таблицы movwf TBLPTRL,ACCESS ; movf TBLPTRH,W,ACCESS ; Старший байт btfss _C ; Если в прошлом вычитании Заем incfsz WREG,W,ACCESS ; Увеличим Старший БАЙТ Вычитаемого на 1, sublw high(Table_Sinus+0x800); Из Конца таблицы movwf TBLPTRH,ACCESS ; DoneAdress ; ***** Конец попытки укоротить таблицу вдвое #endif ;; clrf TBLPTRU,ACCESS ; Самый старший указатель таблицы ; ; Знаковые 16 бит синуса (12 бит размах) на без знаковое 16 бит амплитуды (12 бит размах) ;PCPWM_AmpSin:2;,BANKED; Буфер Амплитуды синусоиды после вычислений V/F ;SynMulBuf :8; Буфер для умножения синуса на амплитуду, BANKED ;1) Перемножаем младшие байты: tblrd*+ ; Читаем младший байт синуса из таблицы синусов movf TABLAT,W,ACCESS ; Младший байт 16 бит синуса movwf SynMulBuf+7,BANKED; буферируем - будет нужен ниже mulwf PCPWM_AmpSin+0,BANKED; Буфер Амплитуды синусоиды после вычислений V/F младший байт movff16 PRODL,SynMulBuf ; спасаем результат tblrd*+ ; Читаем старший байт синуса movf TABLAT,W,ACCESS ; Старший байт 16 бит синуса ;2) Перемножаем старшие байты: mulwf PCPWM_AmpSin+1,BANKED; Буфер Амплитуды синусоиды старший байт <0x10 ; Старший байт позже будет отброшен - 24 бита только в результате ; movff16 PRODL,SynMulBuf+2 ; спасаем результат в старшую половину movff PRODL,SynMulBuf+2 ; спасаем результат в старшую половину ; Все 4 байта результата инициализированы - можно складывать в серединку. ;3) старший Sin на младший Amp, прибавляем к середине результата mulwf PCPWM_AmpSin+0,BANKED; Буфер Амплитуды синусоиды после вычислений V/F младший байт ; ArgB,A1B,ArgA,A1A ; в памяти Младший-Старший идут ; Результат будет B=B+A Add16 SynMulBuf+1,BANKED,PRODL,ACCESS; Складываем перекрёст с серединкой ;======== ; clrf WREG,ACCESS; ; ADD16 Macro ; Старший байт позже будет ; addwfc SynMulBuf+3,F,BANKED ; отброшен - 24 бита только в результате ;======== ;4) Младший Sin на старший Amp, прибавляем к середине результата movf SynMulBuf+7,W,BANKED; буфер Sin младшего mulwf PCPWM_AmpSin+1,BANKED; Буфер Амплитуды синусоиды старшой байт ; ArgB,A1B,ArgA,A1A ; в памяти Младший-Старший идут ; Результат будет B=B+A Add16 SynMulBuf+1,BANKED,PRODL,ACCESS; Складываем перекрёст с серединкой ;======== ; clrf WREG,ACCESS; ; ADD16 Macro ; Старший байт позже будет ; addwfc SynMulBuf+3,F,BANKED ; отброшен - 24 бита только в результате ;======== btfss TABLAT,7,ACCESS ; Знак Старший байт 16 бит синуса bra ExitMul ;Sub16 ArgB,A1B,ArgA,A1A ; в памяти Младший-Старший идут ; Результат B=B-A Sub16 SynMulBuf+2,BANKED,PCPWM_AmpSin+0,BANKED; в соответствии с кодом FXM1616S #else ; Прежние 8 бит ;Tab16Load macro A_Arg,TableAdr; Загрузка указателей таблицы 16 бит Tab16Load Angle_8,Table_Sinus ; Замена на макрос для ухода от ввода повторяющегося кода FXMTab1608U SynMulBuf,BANKED,PCPWM_AmpSin,BANKED ; Проверка макроса btfss TABLAT,7,ACCESS ; Знак Старший байт 16 бит синуса bra ExitMul movf PCPWM_AmpSin,W,BANKED; Буфер Амплитуды синусоиды после вычислений V/F; subwf SynMulBuf+2,F,BANKED; со смещением 2 байт #endif ;#ifdef PCPWM_12b ; 12 бит вычисления вместо 8 бит - пробуем на скорость ExitMul ; Отладка показала что здесь имеем знаковое число размаха от 8 355 585/0x7f7f01 до -8 355 585/0x8080FF #ifdef __DEBUG;******* отладчик АКБ покажет movf SynMulBuf+0,W,BANKED; Результат вычислений младший байт movf SynMulBuf+1,W,BANKED; Результат средний0 байт movf SynMulBuf+2,W,BANKED; Результат средний1 байт movf SynMulBuf+3,W,BANKED; старший байт всегда = 0 должен быть #endif ; Для возврата к беззнаковому - надо прибавить эти пол диапазона к результату ;Края диапазона при максимальной амплитуде должны соответствовать 0 и 2048 регистра PDC, середина, которая = 0 = 1024 PDC. ;0=0гр=0000=00000000==средняя точка пвм ;64=90гр=7fff=007f7f01=максимум ПВМ, удвоенный буде FEFE02, после сдвигов - 7F7 ;128=180гр=0000=00000000=средняя точка пвм, после коррекции FEFE02 ;192=270гр=8001=ff8080ff=минимум ПВМ=после коррекции = 00000000000 ;255=359гр=fcdc=fffcdf24=почти ноль, после коррекции = 7c5e25 - почти средняя точка movlw 0x01; ; Складывание 32 бит результата с константой 0x7f7f01 ADDWF SynMulBuf+0,F,BANKED; младший movlw 0x7F; ; Складывание 32 бит результата с константой 0x7f7f01 ADDWFC SynMulBuf+1,F,BANKED; средний-1 movlw 0x7F; ; Складывание 32 бит результата с константой 0x7f7f01 ADDWFC SynMulBuf+2,F,BANKED; средний-2 ; 16 бит синуса * 8 бит амплитуды = 24 бита, прибавляем точку нуля, усекаем до 16 бит. ; 16 бит выходного значения сравниваем с верхним и нижним порогом ограничителей, присваиваем пороги при пересечении. ; вычитаем нижний порог для смещения точки 0. ; Ограниченные 16 бит для превращения в 11-12 бит ШИМ - умножаем на коэффициент 16 бит, ; результат 32 бита усекаем до 11-12 бит ; Вычитание нижнего порога 1/10 с обнулением при заёме movlw low(0xFFFF/0xA);,W ,A1A ; Младший байт 10% от 0xFFFF subwf SynMulBuf+1,F,BANKED ; Вычитаем А из В, результат в: В=B-A movlw high(0xFFFF/0xA);,W,A1A ; Старший байт, 10% от 0xFFFF ; btfss _C ; Если в прошлом вычитании Заем ; incfsz ArgA+1,W,A1A ; Увеличим Старший БАЙТ Вычитаемого на 1, subwfb SynMulBuf+2,F,BANKED ; и вычтем старшие байты - результат в В #ifdef PCPWM_Board; Yes ; Плата настольная без периферии/контроля условий запуска bnc ZeroPoint ;При заёме - выход на минимум для синхро учебной платы #else bnc BotWithoutPWM;При заёме - обнуление выхода в боевой плате #endif ; Вычитание удвоенного порога 1/5 с присвоением Макс при отсутствии заёма movlw low(0xFFFF-0xFFFF/0x5);,W ,A1A ; Младший байт 10% от 0xFFFF subwf SynMulBuf+1,W,BANKED ; Вычитаем А из В для сравнения movlw high(0xFFFF-0xFFFF/0x5);,W,A1A ; Старший байт, 10% от 0xFFFF subwfb SynMulBuf+2,W,BANKED ; и вычтем старшие байты - результат в В bc MaxPoint ;При отсутствии заёма - Максимальное значение ; Выходное значение зажато между границами, теперь его надо отмасштабировать из ХХХХ в строго 11 бит например ; PCPWM_MK1+0 присваивается в \Init_PCPWM_3F.inc:217 ;FXM1616U2 macro D_Arg,A1D,A_Arg,A1A,B_Arg,A1B,_Work,A1W; ; Подразумевается в памяти Младший-Старший байт идут ; FXM1616U2 SynMulBuf+4, bnk, SynMulBuf+1, bnk, PCPWM_MK1+0, bnk, SynMulBuf+0, bnk; Умножаем на коэфф ; FXM1680U SynMulBuf+4, bnk, SynMulBuf+1, bnk, PCPWM_MK1+0, bnk;, SynMulBuf+0, bnk; Умножаем на коэфф FXM1680U2 SynMulBuf+4, bnk, SynMulBuf+1, bnk, PCPWM_MK1+0, bnk;, SynMulBuf+0, bnk; Умножаем на коэфф movff PRODL,PDC_16L ; Младший модулятор movff PRODH,PDC_16L-1 ; Старший модулятор ; movff SynMulBuf+6,PDC_16L ; Младший модулятор ; movff SynMulBuf+7,PDC_16L-1 ; Старший модулятор bra Done MaxPoint: ; 05/01/2019 отлаживал верхнюю полку на осциллограммах подробно ; В момент равенства PDC=4*PTPer-DTCon - наблюдается глюк формирователя DT - одновременное ; открытие транзисторов на малое время ~ 0.1 мкСек. ;PcPwmPdcMax :2;F,BANKED; Значение PDC верхней полки - не портим ; movf DTCON,W,ACCESS ; Вычитаемое #1 - Dead Time Unit movf PcPwmTopDT,W,BANKED; Вычитаемое #2 = Интервал времени для заряда конденсаторов при верхней полке bz TopWithoutCharge ; При нулевом времени - ничего не вычитаем movff PcPwmPdcMax+1,SynMulBuf+0 ; Буферок старшего байта для заёмов subwf PcPwmPdcMax+0,W,BANKED ; Уменьшаемое, результат в АКБ btfss _C ; Инверсный заём decf SynMulBuf+0,F,BANKED ; Отработка заёма bsf _C ; Чистим инверсный заём subfwb DTCON,W,ACCESS ; Вычитаемое #1 - Dead Time Unit ; Инверсный заём формируем btfss _C ; Инверсный заём decf SynMulBuf+0,F,BANKED ; Отработка заёма movwf PDC_16L,ACCESS ; Мл.модулятор верхней полки movff SynMulBuf+0,PDC_16L-1;,ACCESS ; Ст.модулятор верхней полки bra Done TopWithoutCharge movff PcPwmPdcMax+0,PDC_16L;,ACCESS; Мл.модулятор верхней полки movff PcPwmPdcMax+1,PDC_16L-1;,ACCESS; Ст.модулятор верхней полки bra Done ZeroPoint: ; Выходное значение =0, пропуск умножения и сравнения верхнего порога ; Двойной защитный интервал времени PDC - численно равен значению DTCON - по причине вдвое более ; высокой тактовой генератора DT. ; В момент равенства PDC=DTCon - наблюдается глюк формирователя DT - одновременное ; открытие транзисторов на малое время ~ 0.1 мкСек. ; ***** При этом равенстве глюк модуля формирования DT - *** отсутствие *** защитного интервала.***** ; Для преодоления глюка - надо программно обеспечить минимальное значение модулятора ВЫШЕ счётчика DT. ; clrf SynMulBuf+0,BANKED ; Буферок старшего байта для переноса movf PcPwmTopDT,W,BANKED; Слагаемое #1 = Интервал времени для заряда конденсаторов при верхней полке bz BotWithoutPWM ; При нулевом времени - ничего не складываем addwf DTCON,W,ACCESS ; Слагаемое №2 btfsc _C ; incf SynMulBuf+0,F,BANKED ; Буферок старшего байта для переноса movwf PDC_16L,ACCESS ; Младший модулятор movff SynMulBuf+0,PDC_16L-1;,ACCESS; Ст.модулятор ; movlf 0x19,PDC_16L,ACCESS ;Отладка Младший модулятор bra Done BotWithoutPWM clrf PDC_16L,ACCESS ; Младший модулятор clrf PDC_16L-1,ACCESS ;; Старший модулятор Done: ; call DelayCuriosity ; Исследование запаса по быстродействию обработчика endm ; Конец описания одинакового кода. Для быстроты и простоты - в макро а не в саб проге. ;*******************************************************************************************