@.CHARSET  CP1251

@ GNU AS
.syntax unified
.cpu cortex-m4
.thumb
.fpu fpv4-sp-d16

.include  "/src/inc/i2c.inc"

.EQU  MAX_CICLE_DELAY, 2000 * 1024    @ ~1,3s 100MHz, ~5s (1000 * 1024)
@ .EQU  AM2320_ADDR   , 0xb8
.EQU  AM2320_ADDR_TX, 0xb8 @ 0xb8   (SLAVE ADDRESS)
.EQU  AM2320_ADDR_RX, 0xb9 @ 0xb9
.EQU  RX            , 1
.EQU  TX            , 0

.EQU  I2C_NO_ERROR  , 0
.EQU  I2C_BUSY      , 1
.EQU  I2C_START_ERROR, 2
.EQU  I2C_CRC_ERROR , 3

@                                                                                                                        BUSY
@                                                                                                                     TRA|MSL         TxE    ADDR
@ /* --EV6 */                                                                                                           |||           |      |
@ #define I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ((uint32_t)0x00070082) /* BUSY, MSL, ADDR, TXE and TRA flags */   0111 0000 0000 1000 0010
@ #define I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED    ((uint32_t)0x00030002) /* BUSY, MSL and ADDR flags */             0011 0000 0000 0000 0010
@                                                                                                               {   ...SR2} {       SR1       }
@

@ .EQU I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, 0x00070082 @ /* BUSY, MSL, ADDR, TXE and TRA flags */   0111 0000 0000 1000 0010
@ .EQU I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED,    0x00030002 @ /* BUSY, MSL and ADDR flags */             0011 0000 0000 0000 0010


@ упрощенно: FIXME
.EQU I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, 0x00000082 @ /* BUSY, MSL, ADDR, TXE and TRA flags */   0111 0000 0000 1000 0010
.EQU I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED,    0x00000002 @ /* BUSY, MSL and ADDR flags */             0011 0000 0000 0000 0010


.section .asmcode

@.desc name=AM2320_INIT type=proc
@ ****************************************************************************
@ *                         Инициализация AM2320                             *
@ *  i2c к этому времени уже должен быть настроен                            *
@ ****************************************************************************
@.enddesc
.global AM2320_INIT
AM2320_INIT:
                    PUSH            { LR }
                    POP             { PC }


@.desc name=AM2320_CRC16 type=proc
@ ****************************************************************************
@ *  Подсчёт контрольной суммы принятых данных датчика AM2320                *
@ *                                                                          *
@ ****************************************************************************
@ * Входные параметры:                                                       *
@ * R2 - указатель на буфер с данными                                        *
@ * R1 - размер буфера                                                       *
@ * Функция возвращает:                                                      *
@ * R0 - контрольная сумма                                                   *
@ ****************************************************************************
@.enddesc
AM2320_CRC16:                                     @unsigned int CRC16(uint8_t *ptr, uint8_t length)
                    PUSH            { R3 - R6}
                    LDR             R0, =0xFFFF    @      unsigned int crc = 0xFFFF;
                    MOV             R4, 0
                    LDR             R5, =0xA001
                    MOV             R6, 0x01
next_byte_C:                                      @      while(length--) {
                    LDRB            R4, [ R2 ], 1 @        crc ^= *ptr++;
                    EOR             R0, R0, R4    @
                    MOV             R3, 8         @        uint8_t s = 0x00;
next_bit_C:                                       @        for(s = 0; s < 8; s++) {
                    TST             R0, R6        @          if((crc & 0x01) != 0) {
                    ITTE            NE
                    LSRNE           R0, R0, 1     @            crc >>= 1;
                    EORNE           R0, R0, R5    @            crc ^= 0xA001; }
                    LSREQ           R0, R0, 1     @          else crc >>= 1;

                    SUBS            R3, R3, 1     @
                    BNE             next_bit_C    @        }

                    SUBS            R1, R1, 1
                    BNE             next_byte_C   @      }

                    POP             { R3 - R6}
                    BX              LR            @      return crc;

@.desc name=AM2320_ReadData type=proc
@ ****************************************************************************
@ *  Прием данных о температуе и влажности с датчика AM2320                  *
@ *                                                                          *
@ ****************************************************************************
@ * Функция возвращает:                                                      *
@ * R0 - контрольная сумма, если сошлась или код ошибки в других случаях     *
@ * R1 - температура * 10                                                    *
@ * R2 - влажность * 10                                                      *
@ ****************************************************************************
@.enddesc
.global AM2320_ReadData
AM2320_ReadData:    @ AM2320_ReadData(float *h,float *t)
                    PUSH            { R4 - R10, LR }
                    MOV             R1, 1
                    LDR             R2, = I2C1 + I2C_DR
                    LDR             R3, = PERIPH_BB_BASE + ( I2C1 + I2C_CR1 ) * 32
                    LDR             R4, = PERIPH_BB_BASE + ( I2C1 + I2C_SR1 ) * 32
                    LDR             R10, = PERIPH_BB_BASE + ( I2C1 + I2C_SR2 ) * 32
                    LDR             R5, = I2C1 + I2C_SR2
                    LDR             R6, = I2C1 + I2C_SR1
@=========Инициализация буфера======================================
                    LDR             R9, = buf
                    MOV             R0, 0
                    STR             R0, [ R9 ], 4
                    STR             R0, [ R9 ]
@=========Acknowledge enable========================================
               @ устанавливается бит ACK в регистре CR1, который разрешает модулю генерировать условие ACK после приёма байтов
                    STR             R1, [ R3, I2C_CR1_ACK_N * 4]  @ I2C1->CR1 |= I2C_CR1_ACK;//Acknowledge enable
@============================wake sensor============================
                    BL              wait_not_busy
                    MOV             R9, MAX_CICLE_DELAY
                    CMP             R0, R9
                    BEQ             exit_error_i2c_busy

                    STR             R1, [ R3, I2C_CR1_START_N * 4 ]    @I2C1->CR1 |= I2C_CR1_START;// формирование сигнала старт
                    BL              wait_SB
                    MOV             R9, MAX_CICLE_DELAY
                    CMP             R0, R9
                    BEQ             exit_start_error

                    MOV             R7, AM2320_ADDR_TX
                    STRB            R7, [ R2 ]         @ I2C1->DR = AM2320_ADDR_TX;// передаем адрес датчика I2C1->DR = AM2320_ADDR;

                    MOV             R0, 2
                    BL              SYSTICK_DELAY      @ не ждем пока он нам ответит, т.к.спит

                    STR             R1, [ R3, I2C_CR1_STOP_N * 4 ]    @ I2C1->CR1 |= I2C_CR1_STOP ;// формирование сигнала "Стоп"

@=================================================================
                    BL              wait_not_busy      @ старт последовательность с TX адресом
                    MOV             R9, MAX_CICLE_DELAY
                    CMP             R0, R9
                    BEQ             exit_error_i2c_busy

                    MOV             R1, 1
                    STR             R1, [ R3, I2C_CR1_START_N * 4 ]    @ I2C1->CR1 |= I2C_CR1_START;   // формирование сигнала старт
                    BL              wait_SB
                    MOV             R9, MAX_CICLE_DELAY
                    CMP             R0, R9
                    BEQ             exit_start_error

                    MOV             R0, TX
                    MOV             R7, AM2320_ADDR_TX
@                    ADD             R7, R7, R0       @ RX/TX
                    STRB            R7, [ R2 ]
                    BL              wait_EV6
@=================================================================
                                   @ отправляем команду на чтение данных с датчика
                    MOV             R8, 3              @ read operation
                    STRB            R8, [ R2 ]         @  I2C1->DR = 0x03;
                    BL              wait_TXE

                    MOV             R8, 0              @ starting address
                    STRB            R8, [ R2 ]         @  I2C1->DR = 0x00;
                    BL              wait_TXE

                    MOV             R8, 4              @ number of bytes to read
                    STRB            R8, [ R2 ]         @  I2C1->DR = 0x04;
                    BL              wait_TXE

                    STR             R1, [ R3, I2C_CR1_STOP_N * 4 ]    @ I2C1->CR1 |= I2C_CR1_STOP ;// формирование сигнала "Стоп"
@===== Чтение данных с сенсора =====================================
                    BL              wait_not_busy      @ старт последовательность с RX адресом
                    MOV             R9, MAX_CICLE_DELAY
                    CMP             R0, R9
                    BEQ             exit_error_i2c_busy

                    MOV             R1, 1
                    STR             R1, [ R3, I2C_CR1_START_N * 4 ]    @ I2C1->CR1 |= I2C_CR1_START;   // формирование сигнала старт
                    BL              wait_SB
                    MOV             R9, MAX_CICLE_DELAY
                    CMP             R0, R9
                    BEQ             exit_start_error

                    MOV             R0, RX
                    MOV             R7, AM2320_ADDR_RX
@                    ADD             R7, R7, R0       @ RX/TX
                    STRB            R7, [ R2 ]
                    BL              wait_EV6
@===================================================================

                    LDR             R9, = buf
                    MOV             R7, 8
read_next_byte:     @ //читаем 8 байт данных
                    BL              wait_RXNE
                    LDRB            R8, [ R2 ]    @     buf[i]=I2C1->DR;
                    STRB            R8, [ R9 ], 1
                    SUBS            R7, R7, 1
                    BNE             read_next_byte

                    STR             R1, [ R3, I2C_CR1_STOP_N * 4 ]    @ I2C1->CR1 |= I2C_CR1_STOP ;// формирование сигнала "Стоп"
@=========Acknowledge disable========================================
                    MOV             R8, 0
                    STR             R8, [ R3, I2C_CR1_ACK_N * 4]  @ Acknowledge disable
@=========================CRC check=================================
                    LDR             R9, = buf

                    MOV             R1, 6
                    MOV             R2, R9
                    BL              AM2320_CRC16        @ R0 - CRC16

@                    LDRB            R3, [ R9, 7 ]      @  unsigned int Rcrc = buf[7] << 8;
@                    LSL             R3, R3, 8
@                    LDRB            R1, [ R9, 6 ]      @  Rcrc += buf[6];
@                    ADD             R3, R3, R1
                    LDRH            R3, [ R9, 6 ]       @ одна команда вместо четырёх


                    CMP             R3, R0    @  if (Rcrc == CRC16(buf, 6)) {
                    BNE             exit_CRC_error

                    LDRH            R1, [ R9, 4 ]       @ temperature = ((buf[4] & 0x7F) << 8) + buf[5];
                    REV16           R1, R1
@          *t = temperature / 10.0;
@          *t = (((buf[4] & 0x80) >> 7)== 1) ? ((*t) * (-1)) : *t ; // температура может быть отрицательрой
@          unsigned int humidity = (buf[2] << 8) + buf[3];
                    LDRH            R2, [ R9, 2 ]
                    REV16           R2, R2
                    B               exit_ard
@          *h = humidity / 10.0;
@          return 0;
@  }
exit_CRC_error:     MOV             R0, I2C_CRC_ERROR
                    B               exit_error
exit_start_error:   MOV             R0, I2C_START_ERROR
                    B               exit_error
exit_error_i2c_busy:MOV             R0, I2C_BUSY
exit_error:
                    MOV             R1, 0
                    MOV             R2, 0
exit_ard:           POP             { R4 - R10, PC }


@.DESC     name=DelayR0 type=proc
@ ***************************************************************************
@ *           Цикл на заданное число отсчетов                               *
@ ***************************************************************************
@ | Параметры: R0 - число циклов ожидания                                   |
@ | Возвращаемое значение: R0 = 0                                           |
@ +-------------------------------------------------------------------------+
.global DelayR0
DelayR0:            SUBS            R0, R0, 1
                    BNE             DelayR0
                    BX              LR



.SECTION       .bss
.ALIGN         4
.global buf
buf:                .SPACE          8
@ |----------------------|----------------------|------------------|---------------------|-------------|
@ |8 bit: I 2 C data+W/R | 8 bit: Function Code | 16 bit: humidity | 16 bit: temperature | 16 bit: CRC |
@ |----------------------|----------------------|------------------|---------------------|-------------|

