{ ---------------------------------------------------------------------	}
{	Функции для работы с вводом данных с АЦП										}
{ ---------------------------------------------------------------------	}

{ *********************************************************************	}
{ пропускаем первые три отсчета с АЦП (при вводе данных с ЦАП)				}
{ *********************************************************************	}
WaitForAdcData:
{ перейдем на второй банк регистров													}
	ENA SEC_REG;

{ установим следующий канал															}
	AR = PM(I5, M5); IO(SET_ADC_CHANNEL) = AR;
{ пропустим первые осчеты																}
	AF = AF - 0x1; IF NE RTI;
{ AF - теперь текущий счетчик отсчетов в кадре									}
	AF= PASS AX0;
{ установим обработчик прерываний IRQE для ввода данных с АЦП				}
	I7=^GetAdcData;

{ спокойно выходим из прерывания														}
	RTI;

{ *********************************************************************	}
{ получение данных с АЦП (при вводе данных с ЦАП)								}
{ *********************************************************************	}
GetAdcData:
{ перейдем на второй банк регистров													}
	ENA SEC_REG;

{ установим следующий канал															}
	AR = PM(I5, M5); IO(SET_ADC_CHANNEL) = AR;

{ чтение данных с АЦП																	}
	AR = IO(READ_ADC);
{ произведём корректировку полученного значения									}
	AR = AR + AY1, AY1 = PM(I6,M6);
	MR = AR * MY1(SU), MY1 = PM(I6,M6);
	MR = MR(RND);
{ положим скорректированное значение с АЦП в буфер								}
	DM(I3, M3) = MR1;

{ спокойно выходим из прерывания														}
	RTI;

{ *********************************************************************	}
{ запуск ввода данных с АЦП															}
{ *********************************************************************	}
AdcInputTypeStart:
{ проинициализируем необходимые указатели и переменные ввода данных		}
	CALL InitAdcInputPointers;
{ установим первой канал для работы АЦП											}
	CALL SetAdcFirstChannel;
{ задержка на установление аналогового тракта									}
	CALL SettlingDelay;

{ проверим тип синхронизации при вводе данных									}
	GetPm(AR, SynchroTypeAddr); NONE = PASS AR;
	IF NE JUMP Synchronization;	{ если есть синхр., то прыгаем на нее	}

{ установим флаг разрешения ввода данных											}
	PutValPm(AR, 0x1, InputEnableAddr);

{ сбросим все запросы на прерывания кроме SPORT0 Transmit (вывод)			}
	IFC = 0xBF; NOP;

{ запустим требуемый режим сбора данных											}
	CALL StartRead;

{ завершим выполнение текущей команды												}
	JUMP EndOfCommand;
	
{ ********************************************************************  }
{ запускаем ввод данных																	}
{ ********************************************************************  }
StartRead:
{ размаскируем прерывания IRQE(ввод) и IRQ2(команда)							}
	GetPm(AR, ImaskValueAddr);
	AR = SETBIT 4 OF AR;			{ размаскируем прерывания IRQE(ввод)		}
	PutPm(AR, ImaskValueAddr);
	IMASK = AR; NOP;

{ установка источника тактовых импульсов											}	
	CALL SetInputClockSource;

{ посмотрим на источник тактовых импульсов 										}
	GetPm(AR, InputClockSourceAddr); NONE = PASS AR; IF NE RTS;
	
{ для внутренних тактовых импульсов установим требуемую частоту ввода 	}
	GetPm(AR, InputRateAddr);
	DM(Sport1_Sclkdiv) = AR;		{ 0x3FF5 - Serial Clock Divide Modulus	}

{ запустим ввод данных, включив клоки SCLK , т.е. сделаем их внутренним	}
	AR = 0x7F1F; 						{ 0111 1111 0001 1111 						}
	DM(Sport1_Ctrl_Reg) = AR; 		{ 0x3FF2 - SPORT1 Control Register		}

{ спокойно выходим из функции															}
	RTS;

{ *********************************************************************	}
{ Установка указателей для ввода данных с АЦП									}
{ *********************************************************************	}
InitAdcInputPointers:
{ подготовим массив с корректировочными коэффициентами 						}
	CALL FillCalibrCoef;
{ установим требуемые размеры FIFO буфера ввода									}
	CALL CheckInputFifoLimits;

{ половина длины FIFO буфера ввода													}
	GetPm(AR, CurInputFifoLengthAddr);
	SR= LSHIFT AR BY -1 (LO);
	PutPm(SR0, InputFifoLengthOver2Addr);

{ Set Input Fifo Parameters (указатель на 'голову' FIFO ввода)				}
	GetPm(AR, InputFifoBaseAddressAddr);
	I3 = AR;
	M3 = 0x1;
	GetPm(AR, CurInputFifoLengthAddr);
	L3 = AR;

{ указатель на 'хвост' FIFO буфера ввода											}
	I2 = I3;
{ в M2 должна быть половина длины FIFO буфера ввода							}
	GetPm(AR, InputFifoLengthOver2Addr);
	M2 = AR;
	L2 = L3;

{ Set pointer to ControlTable															}
	I5 = ^ControlTable;
	M5 = 0x1;
	GetPm(AR, ControlTableLenghtAddr); 	{ длина управляющей таблицы		}
	L5 = AR;

{ массив коэффициентов для корректировки смещения нуля и масштаба АЦП	}
	I6 = ^CalibrationArray;
	M6 = 0x1;
	GetPm(AR, ControlTableLenghtAddr); 	{ длина управляющей таблицы		}
	SR = LSHIFT AR BY 1 (LO);				{ умножим на два						}
	L6 = SR0;

{ по месту метки MainLoop пропишем код CALL PutInputData						}
	I4 = ^MainLoop; AR = ^PutInputData; CALL ModifyCall;

{ установим обработчик прерываний IRQE (АЦП)										}
	I7 = ^WaitForAdcData;

	ENA SEC_REG;						{ перейдем на второй банк регистров		}
		AR = 0x4; AF= PASS AR;		{ AF - кол-во отсчетов ожидания 			}
		AY1 = PM(I6,M6);				{ коэф. корректировки смещения нуля		}
		MY1 = PM(I6,M6);				{ коэф. корректировки масштаба			}
	DIS SEC_REG;					  	{ перейдем на первый банк регистров		}

{ спокойно выходим из функции															}
	RTS;

{ *********************************************************************	}
{ сформируем массив с корректировочными коэффициентами 						}
{ *********************************************************************	}
FillCalibrCoef:
{ установим указатели для корректировки входных данных						}
	I5 = ^ControlTable; M5 = 0x1; L5 = 0x0;

	I6 = ^CalibrationArray; M6 = 0x1;
	GetPm(AR, ControlTableLenghtAddr); 	{ длина управляющей таблицы		}
	SR = LSHIFT AR BY 1 (LO);				{ умножим на два						}
	L6 = SR0;

{ разрешена ли корректировка входных данных										}
	GetPm(AY0, IsCorrectionEnabledAddr); NONE = PASS AY0;
	IF EQ CALL DisAdcDataCorrection;
	NONE = PASS AY0;
	IF NE CALL EnaAdcDataCorrection;

{ спокойно выходим из функции															}
	RTS;

{ *********************************************************************	}
{ Если корректировка нужна - формируем массив корректировочными. коэф. 	}
{ при этом каждому каналу АЦП соответствует свой корректировочный 		}
{ коэффициент смещения нуля и масштаба												}
{ *********************************************************************	}
EnaAdcDataCorrection:
	GetPm(AR, ControlTableLenghtAddr);	{ длина управляющей таблицы		}
	CNTR = AR; AY0 = 0x7;
	DO CtrlLoop UNTIL CE;
{ выделяем из управляющей таблицы номер канала АЦП								}
		AR = PM(I5, M5); AR = AR AND AY0;
		M7 = AR;

{	 	Set ZeroOffset																		}
		I7 = ^ZeroOffset;
		MODIFY(I7,M7);
		AR = PM(I7,M7);
		PM(I6,M6) = AR;

{	 	Set ScaleFactor																	}
		I7 = ^ScaleFactor;
		MODIFY(I7,M7);
		AR = PM(I7,M7);
		PM(I6,M6) = AR;
CtrlLoop: NOP;

{ спокойно выходим из функции															}
	RTS;

{ *********************************************************************	}
{ Если корректировка не нужна, готовим соответствующий массив				}
{ при этом всем каналам АЦП соответствует одинаковый корректировочный 	}
{ коэффициент смещения нуля и масштаба												}
{ *********************************************************************	}
DisAdcDataCorrection:
	GetPm(AR, ControlTableLenghtAddr);	{ длина управляющей таблицы		}
	CNTR = AR;
	DO CtrlLoop1 UNTIL CE;
{	 	Set ZeroOffset																		}
		AR = 0x0000; PM(I6,M6) = AR;
{	 	Set ScaleFactor																	}
		AR = 0x8000; PM(I6,M6) = AR;
CtrlLoop1: 	NOP;

{ спокойно выходим из функции															}
	RTS;

{ *********************************************************************	}
{	Установка первого канала для работы АЦП										}
{ *********************************************************************	}
SetAdcFirstChannel:
	AR = PM(I5, M5); IO(SET_ADC_CHANNEL) = AR;
	RTS;

{ ********************************************************************  }
{ задержка установление аналогового тракта										}
{ ********************************************************************  }
SettlingDelay:
	CALL Delay2mks;
	RTS;

{ *********************************************************************	}
{ Команда ввода кадра отсчетов (если возможно)									}
{ *********************************************************************	}
Read_Kadr_cmd:
{ а работа ввод данных разрешен?														}
	GetPm(AR, InputEnableAddr); NONE = PASS AR; IF NE JUMP EndOfCommand;

{ останов сбора данных																	} 
	CALL StopRead;

{ проинициализируем необходимые указатели и переменные ввода данных		}
	CALL InitAdcInputPointers;
{ установим первый канал для работы АЦП											}
	CALL SetAdcFirstChannel;
{ задержка на установление аналогового тракта									}
	CALL SettlingDelay;

{ а по месту метки MainLoop надо прописать код CALL GetInputKadr			}
	I4 = ^MainLoop; AR = ^GetInputKadr; CALL ModifyCall;

{ запустим требуемый режим сбора данных											}
	CALL StartRead;

{ выходим из команды не завершив её окончательно								}
	RTS;

{ *********************************************************************	}
{ Функция ввода одного кадра отсчетов с АЦП										}
{ *********************************************************************	}
GetInputKadr:
{ а не готовы ли уже данные кадра?													}
	AR = I3;									{ получим 'голову' FIFO ввода			}
	AY0 = I2;  								{ получим 'хвост' FIFO ввода 			}
	AR = AR - AY0;
	GetPm(AY0, CurInputFifoLengthAddr);{ текущая длина FIFO буфера ввода	}
	IF LT AR = AR + AY0;		{ теперь в AR истинная разница между I3 и I2	}
	GetPm(AY0, ControlTableLenghtAddr);	{ длина управляющей таблицы		}
	NONE = AR - AY0; 						{ сравним эти величины					}
	IF LT RTS;								{ если меньше, то выйдем				}

{ по месту метки MainLoop пропишем код CALL PutInputData						}
	I4 = ^MainLoop; AR = ^PutInputData; CALL ModifyCall;

{ завершим выполнение команды однократного чтения кадра отсчётов с АЦП	}
	JUMP Stop_Read_cmd;

{ *********************************************************************	}
{ Команда ввода однократного отсчета с АЦП (если возможно)					}
{ *********************************************************************	}
Read_Sample_cmd:
{ а ввод данных разрешен?																}
	GetPm(AR, InputEnableAddr); NONE = PASS AR;
	IF NE JUMP EndOfCommand;

{ останов сбора данных																	} 
	CALL StopRead;

{ установим требуемый аналоговый канал для однократного чтения с АЦП		}
	GetPm(AR, InputChannelAddr); IO(SET_ADC_CHANNEL) = AR;
{ задержка на установление аналогового тракта									}
	CALL SettlingDelay;

{ установим новый обработчик прерываний IRQE	 									}
{										специально для аналоговой синхронизации	}
	I7 = ^WaitForAdcSample;

{ а по месту метки MainLoop надо прописать код CALL AdcSampleIdle			}
	I4 = ^MainLoop; AR = ^AdcSampleIdle; CALL ModifyCall;

{ флажое-признак наличия отсчёта с АЦП												}
	MR0 = 0x0;
	ENA SEC_REG;						{ перейдем на второй банк регистров		}
		AR = 0x4; AF = PASS AR;		{ AF - кол-во отсчетов ожидания			}
	DIS SEC_REG;					  	{ перейдем на первый банк регистров		}

{ сбросим флажок-признак наличия готового отсчёта с АЦП						}
	SI = 0x0;

{ определим какой канал будет использоваться для корректировки				}	
	GetPm(AR, InputChannelAddr);	PutPm(AR, CorrectableInputChannelAddr);
{ определимя с корректировочными корректировочными коэф. исполь. канала	}
	CALL GetCalibrationCoef;

{ установим частоту ввода данных равную 1000 кГц								}
	AR = 71;
	DM(Sport1_Sclkdiv) = AR;		{ 0x3FF5 - Serial Clock Divide Modulus	}

{ размаскируем прерывания IRQE(ввод) и IRQ2(команда)							}
	GetPm(AR, ImaskValueAddr);
	AR = SETBIT 4 OF AR;			{ размаскируем прерывания IRQE(ввод)		}
	PutPm(AR, ImaskValueAddr);
	IMASK = AR; NOP;

{ запустим ввод данных, включив клоки SCLK1, т.е. сделаем их внутренним	}
	AR = 0x7F1F; 						{ 0111 1111 0001 1111 						}
	DM(Sport1_Ctrl_Reg) = AR; 		{ 0x3FF2 - SPORT1 Control Register		}

{ спокойно выходим из функции, до конца не выполнив команду					}
	RTS;

{ *********************************************************************	}
{ функция ожидания однократного отсчёта АЦП										}
{ *********************************************************************	}
AdcSampleIdle:
{ проверим наличие готового отсчёта с АЦП											}
	AR = SI; NONE = PASS AR; IF EQ RTS;

{ в TempAdcSample находится скорректированный код с требуемого канала АЦП}
	AR = DM(TempInputSample); PutPm(AR, InputSampleAddr);
{ теперь по месту метки MainLoop пропишем код CALL PutInputData			}
	I4 = ^MainLoop; AR = ^PutInputData; CALL ModifyCall;
{ завершим выполнение команды однократного чтения с АЦП						}
	JUMP Stop_Read_cmd;

{ *********************************************************************	}
{ пропускаем первые три отсчета с АЦП (при вводе данных с АЦП)				}
{ *********************************************************************	}
WaitForAdcSample:
{ перейдем на второй банк регистров													}
	ENA SEC_REG;
{ пропустим первые прерывания от АЦП												}
	AF = AF - 0x1; IF NE RTI;
{ установим обработчик прерываний IRQE для ввода данных с АЦП				}
	I7 = ^GetAdcSample;
{ спокойно выходим из прерывания														}
	RTI;

{ *********************************************************************	}
{ обработчик прерывания для получения отсчёта с АЦП							}
{ *********************************************************************	}
GetAdcSample:
{ перейдем на второй банк регистров													}
	ENA SEC_REG;

{ считаем значение с текущего канала АЦП											}
	AR = IO(READ_ADC);
{ корректировка смещения																}
	AR = AR + AY1;
{ корректировка масштаба																}
	MR = AR * MY1(SU);
{ округление результата																	}
	MR = MR(RND);
{ положим скорректированный отсчёт с АЦП во временную переменную			}
	Dm(TempInputSample) = MR1;
	
{ перейдем на первый банк регистров													}
	DIS SEC_REG; 						
	
{ установим флажок-признак, что есть необработанное прерывание от АЦП	}
	SI = 0x1;

{ выходим из обработчика прерывания													}
	RTI;

{ *********************************************************************	}
{ определимся с корректировочными коэффициентами								}
{ *********************************************************************	}
GetCalibrationCoef:
{ умолчательные корректировочные коэф. смещения и усиления для АЦП		}
	AR = 0x0000; DM(TempArray + 0) = AR;
	AR = 0x8000; DM(TempArray + 1) = AR;

{ разрешена ли корректировка входных данных										}
	GetPm(AR, IsCorrectionEnabledAddr); NONE = PASS AR; IF EQ JUMP FillCorrectionCoefs;

{ параметры работы указателя I4														}
	M4 = 0x0; L4 = 0x0;

{ определимся с номером используемого канала АЦП								}
	GetPm(AR, InputChannelAddr); AY0 = 0x7; AR = AR AND AY0;

{ параметры работы указателя I4														}
	M4 = AR;

{ 	Set ZeroOffset																			}
	I4 = ^ZeroOffset; MODIFY(I4, M4);
	AR = PM(I4, M4); DM(TempArray + 0) = AR;

{ 	Set ScaleFactor																		}
	I4 = ^ScaleFactor; MODIFY(I4, M4);
	AR = PM(I4, M4); DM(TempArray + 1) = AR;

{ восстановим параметры работы указателя I4										}
	M4 = 0x0; L4 = 0x0;

{ окончательно разбираемся с корректировочными коэффициентами				}
FillCorrectionCoefs:
	ENA SEC_REG;						{ перейдем на второй банк регистров		}
		AY1 = DM(TempArray + 0);	{ AY1 - корр. коэффциент смещение АЦП	}
		MY1 = DM(TempArray + 1);	{ MY1 - корр. коэффциент масштаб АЦП	}
	DIS SEC_REG;					  	{ перейдем на первый банк регистров		}

{ спокойно выходим из функции															}
	RTS;
