# отследим формирование ответа с отправки
Общий принцип такой:
- MESS_01 (default state)
	- отправляем массив State_Data обычнфм блокирующим способом
- MESS_02 (Transmith packet)
	- Формируем ответ в массиве Long_Data, отправляем (**что?**) через USART_TX_DMA
- MESS_03://Transmith saved packet
	- обновляем данные в UART_DATA, 
	- запускаeм DMA отправку (**чего?**)
	

# отследим путь информации с ADC
hadc1.Init.DMAContinuousRequests = DISABLE;
hadc3.Init.DMAContinuousRequests = DISABLE;

### static uint16_t Get_ADC(uint8_t num):
- num == 0 => запуск ADC1
- num == 1 => возвращает данные ADC1
- num == 2 => stop ADC1
- num == 3 => запуск ADC3
- num == 4 => возвращает данные ADC3
- num == 5 => stop ADC3





## USART_TX(State_Data,2) (main.c:414)
Срабатывает, если UART_transmission_request == Default state (MESS_1)


# при получении 0x7777
1. Decode _uart (main.c:1506)
2. Command копируется в temp2
3. Устанавливаются параметры Curr_setup
	1. WORK_EN
	2. U5V1_EN
	3. U5V2_EN
	4. LD1_EN
	5. REF1_EN
	6. REF2_EN
	7. TEC1_EN
	8. TEC2_EN
	9. TS1_EN
	10. TS2_EN
	11. SD_EN
	12. PI1_RD
	13. PI2_RD
4. Парсится заголовок:
5. Eсли 0x1111:
6. Если 0x7777 -- Устанавливаются параметры task:
	1. task_type
	2. min_param
	3. current_param
	4. max_param
	5. delta_param
	6. dt
	7. tau
	8. sec_param
	9. curr
	10. temp
	11. p_coef_1
	12. i_coef_1
	13. p_coef_2
	14. i_coef_2
	Температурные коэффициенты записываются в соотвестсвующие поля LD1_curr_setup и
7. 





# hardware:
MCU настроен так, что не имеет выходов DAC и TIM. Следовательно ток лазеров задается по цифровому интерфейсу.
- SDMMC1 -- карта памяти
- **SPI2 -- TX**
- SPI4 -- RX
- SPI5 -- RX
- **SPI6 -- TX**
- USART1 -- связь с компом

main.c:1652: //LL_SPI_Enable(SPI6);//Enable SPI for Laser2 DAC -- *Догадка верна!*
Предыдущая строка (main.c:1651): `HAL_GPIO_WritePin(LD2_EN_GPIO_Port, LD2_EN_Pin, GPIO_PIN_SET);
Аналогично в(ы)ключается LD1 (main.c:1638-1647)
Что такое TEC2? `LL_SPI_Disable(SPI2);//Disable SPI for Laser1 DAC & TEC1`

main.c:1739`LL_SPI_TransmitData16(SPI6, DATA);//Transmit word to Laser1 DAC
--строка из функции void Set_LTEC(uint8_t num, uint16_t DATA).
Функция вызывается:
1. (main.c:260) `temp16=PID_Controller_Temp(&LD1_curr_setup, &LD1_param, 1);
	`Set_LTEC(3, temp16);//Drive Laser TEC 1
2. (main.c:262) `Set_LTEC(4, temp16);//Drive Laser TEC 2` -- аналогично предыдущему
3. (main.c:277) `Set_LTEC(1,LD1_curr_setup.CURRENT[Work_counter]);//Drive Laser diode 1` -- установка тока лазера
4. main.c:1717 -- definition Set_LTEC -- LL_SPI_TransmitData16(SPI2, DATA);//Transmit word to Laser1 DAC, нужное устройство выбирается интерфейсом SPI (2 или 6) и сигналом EN через GPIO.

LD1_curr_setup -- структура с полями:
- P_coeff_temp
- I_coeff_temp
- CURRENT  -- массив
Заполнение LD1_curr_setup: -- **происходит при парсинге команды 0x1111**
`for (uint8_t i=0; i<CURRL_16; i++)
`{
`LD1_curr_setup->CURRENT[i] = (uint16_t)(*temp2);
`temp2++;
`}` (main.c:1579-1583)
temp2 -- сдвинутый указатель на массив Command. Многократное увеличение temp2 на единицу -- видимо для расшифровки разных параметров.

# Структура команд
## 0x1111

| Номер | Название   | Код                 | Расшифровка                          |
| ----- | ---------- | ------------------- | ------------------------------------ |
| 0     | Header     | 0x1111              | Заголовок                            |
| 1     | Setup      | 0xXXXX              | Биты настроек                        |
| 2     | LD1_temp   | 16bit float         | Температура лазера 1                 |
| 3     | LD2_temp   | 16bit float         | Температура лазера 1                 |
| 4     | Reserved   | 0x0000              | Зарезервировано                      |
| 5     | Reserved   | 0x0000              | Зарезервировано                      |
| 6     | Reserved   | 0x0000              | Зарезервировано                      |
| 7     | P_temp1    | 16bit float         | Пропорциональный коэффициент для ЛМ1 |
| 8     | I_temp1    | 16bit float         | Интегальный коэффициент для ЛМ1      |
| 9     | P_temp2    | 16bit float         | Пропорциональный коэффициент для ЛМ2 |
| 10    | I_temp2    | 16bit float         | Интегальный коэффициент для ЛМ2      |
| 11    | Message_ID | 16bit uint          | Номер сообщения                      |
| 12    | LD1_curr   | 16bit float***100** | Ток лазера 1                         |
| 13    | LD2_curr   | 16bit float***100** | Ток лазера 2                         |
| 14    | CRC        | 16bit uint          | Контрольная сумма                    |
Итого 213 16-битовых слов.
## 0x7777

| Номер | Название    | Код         | Расшифровка                                                  |                                     |                                                                                       |                                         |
| ----- | ----------- | ----------- | ------------------------------------------------------------ | ----------------------------------- | ------------------------------------------------------------------------------------- | --------------------------------------- |
| 0     | Header      | 0x7777      | Заголовок                                                    | поле в структуре                    | действие                                                                              | ref                                     |
| 1     | Setup       | 0xXXXX      | Биты настроек (как в 0х1111)                                 |                                     |                                                                                       |                                         |
| 2     | TaskType    | 16bit uint  | 0х1 -- меняется ток лазера 1                                 | task.task_type                      |                                                                                       |                                         |
|       |             |             | 0х2 -- меняется ток лазера 2                                 |                                     |                                                                                       |                                         |
|       |             |             | 0х3 -- меняется температура лазера 1                         |                                     |                                                                                       |                                         |
|       |             |             | 0х4 -- меняется температура лазера 2                         |                                     |                                                                                       |                                         |
| 3     | chngd_p_min | 16bit uint  | Минимальное значение изменяемого параметра (mA или C)        | task.min_param = task.current_param | записывается в железный драйвер по SPI `Set_LTEC(task.task_type, task.current_param)` | main.c:373-377. И далее (main.c:384)... |
| 4     | chngd_p_max | 16bit uint  | Максимальное значение изменяемого параметра (mA или C)       | task.max_param                      |                                                                                       |                                         |
| 5     | delta_p     | 16bit uint  | Шаг дискретизации изменяемого параметра (mA или C)           | task.delta_param                    |                                                                                       |                                         |
| 6     | delta_t     | 16bit uint  | Дискретный шаг по времени (мкс)                              | task.dt                             | период TIM10                                                                          | main.c:360                              |
| 7     | fixed_param | 16bit uint  | Значение другого параметра лазера с изменяемым параметром    | task.tau                            |                                                                                       |                                         |
| 8     | I_fixed     | 16bit uint  | Значение тока для лазера с фиксированными параметрами        | task.sec_param                      |                                                                                       |                                         |
| 9     | T_fixed     | 16bit uint  | Значение температуры для лазера с фиксированными параметрами | task.curr                           |                                                                                       |                                         |
| 10    | Tau         | 16bit uint  | Значение тау (время релаксации, миллисекунды)                | task.temp                           |                                                                                       |                                         |
| 11    | P_temp1     | 16bit float | Пропорциональный коэффициент для ЛМ1                         | task.p_coef_1                       |                                                                                       |                                         |
| 12    | I_temp1     | 16bit float | Интегальный коэффициент для ЛМ1                              | task.i_coef_1                       |                                                                                       |                                         |
| 13    | P_temp2     | 16bit float | Пропорциональный коэффициент для ЛМ2                         | task.p_coef_2                       |                                                                                       |                                         |
| 14    | I_temp2     | 16bit float | Интегальный коэффициент для ЛМ2                              | task.i_coef_2                       |                                                                                       |                                         |
| 15    | CRC         | 16bit uint  | Контрольная сумма                                            |                                     |                                                                                       |                                         |

# Общий принцип работы:
С частотой 1кГц:
- Установили ток current\[Work_counter]
- Померяли температуры
- увеличили Work_counter на 1


# получение температуры
Есть 2 подозрительные функции: Get_ADC и MPhD_T.
Что делает PID_Controller_Temp? -- Реализация ПИ контроллера.
### Get_ADC
В строках main.c:286:311 -- вызывается с параметрами 0-5, результат кладется в Long_Data\[CURRL_16\*2+5 -- CURRL_16\*2+10].
CURRL_16 -- макрос для 100.
Вероятно, это `//Prepare DATA of internals ADCs` (main.c:281)
определение Get_ADC(uint8_t num):
	num == 0 => HAL_ADC_Start(&hadc1); // Power on
	num == 1 => ADC1 poll for conversion, return value
	num == 2 => HAL_ADC_Stop(&hadc1); // Power off
		num == 3 => HAL_ADC_Start(&hadc3); // Power on
	num == 4 => ADC3 poll for conversion, return value
	num == 5 => HAL_ADC_Stop(&hadc3); // Power off
=> заполнение массива Long_Data\[CURRL_16\*2 +5:9] == результат измерения ADC1. Затем ADC1 выключается. Long_Data\[CURRL_16\*2+10] == единичное измерение ADC3.
ADC3 -- включен всего один канал.
###### Измеряется один и тот же канал или разные? -- ADC1 -- Разные; ADC3 -- один (единственный включенный)
ADC1 подключено к 5 каналам: IN2, IN8-11.
Конфигурация ADC1:
**Mode: independent**
**Scan conversion mode: enabled** -- после каждого измерения ADC переключается на следующий канал.
**Continuous conversion mode: disabled** -- In continuous conversion mode, the ADC starts a new conversion as soon as it finishes one. -- FALSE
**Discontinuous conversion mode: disabled**  -- По триггеру запускается последовательность из нескольких (ADC_CR1 -> DISCNUM\[2:0]) измерений включенных каналов (ADC_SQRx).
**DMA Continuous Requests: Disabled**
**End of conversion selection: EOC flag at the end of single channel conversion.**

ADC1 и ADC3 -- сконфигурированы одинаково (кроме числа каналов.)
### MPhD_T(uint8_t num) -> uint16_t P
1. медленно дрыгаем ногами SPI(4:5)\_CNV_Pin для //Prepare conversion и //Stop acqusition & start conversion
2. Включаем SPI, ждем получения значения, возвращаем его.
3. Различия между параметрам num(1:4) -- дрыгаем разными ногами и слушаем разные SPI(4 или 5)
4. Ноги: (по 1_1_Report_generator_heterodyne_20240124 1.pdf)^[![[1_1_Report_generator_heterodyne_20240124 1.pdf#page=29]]]

| название          | на железе (по .ioc) | на схеме из report | окончание                                                                       |                                              |
| ----------------- | ------------------- | ------------------ | ------------------------------------------------------------------------------- | -------------------------------------------- |
| ADC_ThrLD1_CS_Pin | PE11                | SPI4_NSS           | [AD7686CRMZ](https://www.analog.com/en/products/ad7686.html#part-details) (ADC) | меряет цепь ThrLD1 -- **подтянутую к 2V5_3** |
| ADC_MPD1_CS_Pin   | PE10                | SPI4_IO1           | [AD7686CRMZ](https://www.analog.com/en/products/ad7686.html#part-details) (ADC) | меряет цепь `100 mV` -- 1/50 от 5VA2         |
[Даташит на AD7686](AD7686.pdf)
6. Читаются:
	1. num == 1 => MPD1
	2. num == 2 => MPD2
	3. num == 3 => ThrLD1
	4. num == 4 => ThrLD2
7. Зачем-то MPhD_T() в коде всегда вызывается 2 раза подряд с одним и тем же аргументом, причем результат первого вызова отбрасывается.
Что такое ThrLD1? -- **Temperature** LaserDiode? ThorlabsLaserDiode?
Что такое MPD1? -- Monitor PhotoDiode1?
### Set_LTEC(uint8_t num, uint16_t DATA)
- num == 1 => запись DATA в DAC_LD1
- num == 2 => запись DATA в DAC_LD2
- num == 3 => запись DATA в DAC_TEC1
- num == 4 => запись DATA в DAC_TEC2
 Куда идут значения MPhD_T(uint8_t num) -> uint16_t adc_val?
# В основном рабочем цикле WORK_ENABLE (main.c:243), каждую 1 мс:
TO7 -- счетчик TIM7_overflow -- происходят каждую 1 мс(? -- согласно комментарию в коде. Можно проверить, найдя источник тактирования TIM7 и зная настройки таймера)
- LD1_param.POWER = MPhD_T(1) (MPD1);//Get Data from monitor photodiode of LD1 **измерили мощность**
- LD1_param.LD_CURR_TEMP = MPhD_T(3); **измерили температуру**
- temp16=PID_Controller_Temp(&LD1_curr_setup, &LD1_param, 1); **рассчитали новую мощность нагревателя лазера
- Set_LTEC(3, temp16);//Drive Laser TEC 1 **отправили новую мощность в DAC нагревателя
- LD1_param.LD_CURR_TEMP -- средняя температура, реализовано через накопитель T1_temp.
- Корректировка нагревателя происходит непрерывно, каждый рабочий цикл (раз в 1 мс)
- Также непрерывно в Long_Data записывается  LDx_param.POWER. LD1 -- в позиции от 0 до CURRL_16-1 (\==99), LD2 -- от 100 до 199.
- В DAC драйвера лазера записывается новая мощность из LD1_curr_setup.CURRENT\[WorkCounter]
- 
- WorkCounter -- счетчик рабочих циклов. Меняется от 0 до 99, затем сбрасывается. При определенных значениях происходит:
	- WorkCounter == 0 => старт нового цикла, 
	- WorkCounter == CURRL_16-8 (=92) -- запись значений внутренних ADC в конец Long_Data\[CURRL_16\*2 + 5:10]. (main.c:284)
	- WorkCounter == CURRL_16-1 (main.c:317)
		- В LDx_param.LD_CURR_TEMP записывается усредненная за весь цикл (WorkCounter от 0 до 99) температура
		- В Long_Data\[CURRL_16\*2+1:2] записывается время с дискретностью 10 мс (т.е. единица времени -- 10 мс)
		- В Long_Data\[CURRL_16\*2+3] записывается LD1_param.LD_CURR_TEMP; (main.c:337)
		- В Long_Data\[CURRL_16\*2+4] записывается LD2_param.LD_CURR_TEMP; (main.c:340)

## Структура Long_Data

| Long_Data индекс                       | значение                                                                                                                                                        | кто пишет                                                                                                                                                                                                    |
| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| 0 : CURRL_16-1       (0:99)            | Измеренная мониторным диодом мощность лазера 1                                                                                                                  | LD1_param.POWER (main.c:269, 274), измеренное MPhD_T(1) (main.c:250)                                                                                                                                         |
| CURR_L16 : CURRL_16\*2-1     (100:199) | Измеренная мониторным диодом мощность лазера 2                                                                                                                  | LD2_param.POWER (main.c:270, 275), измеренное MPhD_T(2) (main.c:252)                                                                                                                                         |
| CURR_L16\*2 +1:2                       | Время в десятках мс                                                                                                                                             | TO6_stop = TO6; и следующие 2 строки (main.c:332:334) (TO6 -- счетчик переполнения таймера TIM6, происходящего каждые 10 мс)                                                                                 |
| Long_Data\[CURRL_16\*2+3]              | Усредненная за цикл варьирования мощности температура лазера 1                                                                                                  | LD1_param.LD_CURR_TEMP (main.c:337)  Усреднение -- main.c:323 и main.c:264. Среднее рассчитывается прямо перед записью в массив. До этого в LD1_param.LD_CURR_TEMP хранится последняя измеренная температура |
| Long_Data\[CURRL_16\*2+4]              | Усредненная за цикл варьирования мощности температура лазера 2                                                                                                  | Аналогично предыдущему                                                                                                                                                                                       |
| Long_Data\[CURRL_16\*2 + 5:10]         | Значения внутренних ADC. Каналы и пины MCU соответственно: \[ADC1_IN2 - PA2, ADC1_IN8 - PB0, ADC1_IN9 - PB1, ADC1_IN10 - PC0, ADC1_IN11 - PC1, ADC2_IN15 - PF5] | Запись происходит когда WorkCounter == CURRL_16-8. main.c:284:311                                                                                                                                            |
| Long_Data\[CURRL_16\*2 + 11]           | //Message ID                                                                                                                                                    | main.c:1577                                                                                                                                                                                                  |
| Long_Data\[DL_16-1] (212)              | Checksum                                                                                                                                                        | main.c:342:348                                                                                                                                                                                               |
Long_Data сохраняется на SD карточку (main.c:342:348)
Long_Data может быть прочитана с SDcard (main.c:216:218)
Long_Data отправляется по UART через DMA (main.c:434:442) или (main.c:420:433), взависимости от UART_transmission_request (если равна MESS_02 или MESS_03)
	Long_Data (uint16_t) преобразуется в UART_DATA (uint8_t), затем вызывается функция  USART_TX_DMA(data_length), запускающая отправку через DMA. DMA контроллер сконфигурирован брать данные из памяти, начиная с указателя UART_DATA (main.c:1437), отправлять в регистр LL_USART_DMA_REG_DATA_TRANSMIT, после чего инкрементировать адрес (main.c:1177), откуда берутся данные. И так data_length раз.
#### Где устанавливается флаг UART_transmission_request?
MESS_03 -- если Long_Data прочитан с SDcard
MESS_02 -- если CPU_state == TRANS_ENABLE
Установка флага CPU_state в состояние TRANS_ENABLE:
	Если UART принял команду 0x4444.
# Обработка команды 0x4444 
1. по UART пришло сообщение. Когда прием сообщения окончился -- вызывается обработчик UART_RxCpltCallback (stm32f7xx_it.c:376)
2. Обработчик читает заголовок сообщения. Если это 0x4444 -- CPU_state устанавливается в TRANS_ENABLE.
3. В основном цикле (main.c:154) проверяется CPU_state. Если это TRANS_ENABLE -- UART_transmission_request устанавливается в MESS_02, CPU_state устанавливается в предыдущее состояние.
4. В том же цикле проверяется состояние UART_transmission_request. Если это MESS_02:
	1. Рассчитывается контрольная сумма массива Long_Data
	2. Long_Data отправляется через DMA на передачу UART
# Режим TASK_ENABLE
0. TIM10 -- установлен на генерацию прерывания и обновление TO10. Предделитель дает один отсчет таймера в 1 мкс.
1. Установили период TIM10 в dt микросекунд. (обновляем TO10) (main.c:357:363)
2. Каждое обновление TO10 через записываем Set_LTEC в DAC, увеличиваем параметр (task.current_param) на task.delta_param, пока не достигнем максимального значения (task.max_param) (main.c:373:379)
3. Останавливаем TIM10, обнуляем счетчики (TO10, TO10_before), task.current_param = min_param;
4. 

# почему при установке min, max тока одного лазера ток другого устанавливается == min первого?
В For_stm32_2023_12_08 — в main.c:339 — при варьировании тока диода 1 — ток диода 2 устанавливается в мин. значение тока диода 1. В main.c:378 — наоборот. Зачем так сделано — непонятно. 
В For_stm32_cubeide -- всё хорошо, токи варьируются независимо.







