Аlex писал(а):Не забывайте, что речь идёт об изучении начинающего. А для такого случая, простота периферии - достоинство.
Не скажу что чем больше периферии тем сложнее с ней работать. Уровень сложности примерно одинаков так что...
Аlex писал(а):На сколько я знаю, винда просто не даст обращаться к регистрам порта напрямую, только через API. По этому написать собственный нормальный драйвер вряд ли получится.
Так я и писал выше о разработке драйвера LPT порта.
http://www.cyberforum.ru/blogs/204791/blog3078.html
Приведу пару примеров (код на бейсике).
Драйвер сообщающий приложению о прерываниях LPT порта (PB_5.11_x86_DriverPack_v2.2.zip\Examples\Driver\Advanced\Interruption\LPT\Driver\LPT_Interrupt.pb).
Спойлер
Код: Выделить всё
; Сделано по материалам сайта http://www.kernelchip.ru/pcports/PS024.php
; http://www.kernelchip.ru/pcports/PS025.php
Declare DriverEntry(*DriverObject, *RegistryPath)
*Point=@DriverEntry()
!jmp [p_Point]
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
EnableExplicit
#PortAddress = $378
#CONTROL = #PortAddress+2
#IOCTL_hEvent = $200
Structure LOCAL_DEVICE_INFO Align #PB_Structure_AlignC
*InterruptObject.KINTERRUPT
Level.l
Vector.l
Affinity.KAFFINITY
*pEventObject.KEVENT
EndStructure
Procedure Isr(*Interrupt.KINTERRUPT, *Context)
Protected *DeviceObject.DEVICE_OBJECT = *Context
IoRequestDpc(*DeviceObject, *DeviceObject\CurrentIrp, #Null)
ProcedureReturn #True
EndProcedure
Procedure DpcRoutine(*Dpc.KDPC, *DeviceObject.DEVICE_OBJECT, *IrpIRP, *Context)
Protected *DeviceExtension.LOCAL_DEVICE_INFO, *pIrp.IRP
*pIrp = *DeviceObject\CurrentIrp
*DeviceExtension = *DeviceObject\DeviceExtension
WRITE_PORT_UCHAR(#PortAddress, 0)
WRITE_PORT_UCHAR(#PortAddress, 60)
If *DeviceExtension\pEventObject
KeSetEvent(*DeviceExtension\pEventObject, 0, #False);
EndIf
ProcedureReturn 0
EndProcedure
Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
Protected ntStatus, *Stack.IO_STACK_LOCATION
Protected inBuffersize, hEvent, *DeviceExtension.LOCAL_DEVICE_INFO
*Stack = IoGetCurrentIrpStackLocation(*pIrp)
inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
ntStatus = #STATUS_SUCCESS
If *pIrp\SystemBuffer And inBuffersize>=4
Select *Stack\Parameters\DeviceIoControl\IoControlCode
Case #IOCTL_hEvent
hEvent = PeekL(*pIrp\SystemBuffer)
If hEvent
*DeviceExtension = *DeviceObject\DeviceExtension
If *DeviceExtension\pEventObject
ObDereferenceObject(*DeviceExtension\pEventObject)
*DeviceExtension\pEventObject=0
EndIf
ObReferenceObjectByHandle(hEvent, #SYNCHRONIZE, #Null, #UserMode, @*DeviceExtension\pEventObject, #Null)
EndIf
Default
ntStatus = #STATUS_UNSUCCESSFUL
EndSelect
Else
ntStatus = #STATUS_BUFFER_TOO_SMALL
EndIf
*pIrp\IoStatus\Information = 0
*pIrp\IoStatus\Status = ntStatus
IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
ProcedureReturn ntStatus
EndProcedure
Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *Irp.IRP)
*Irp\IoStatus\Information = 0
*Irp\IoStatus\Status = #STATUS_SUCCESS
IoCompleteRequest(*Irp, #IO_NO_INCREMENT)
ProcedureReturn #STATUS_SUCCESS
EndProcedure
Procedure DriverUnload(*DriverObject.DRIVER_OBJECT)
Protected uniDOSString.UNICODE_STRING
Protected *Extension.LOCAL_DEVICE_INFO = *DriverObject\DeviceObject\DeviceExtension
; Disable Parallel Port IRQ's
WRITE_PORT_UCHAR(#CONTROL, READ_PORT_UCHAR(#CONTROL) & $EF)
; Disconnect Interrupt
IoDisconnectInterrupt(*Extension\InterruptObject)
If *Extension\pEventObject
ObDereferenceObject(*Extension\pEventObject)
*Extension\pEventObject=0
EndIf
; Delete Symbolic Link
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
IoDeleteSymbolicLink (@uniDOSString)
; Delete Device
IoDeleteDevice(*DriverObject\DeviceObject)
DbgPrint("Unload Driver")
!CALL _PB_EOP ; Освобождение ресурсов.
EndProcedure
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
Protected *DeviceObject.DEVICE_OBJECT, *DeviceExtension.LOCAL_DEVICE_INFO
Protected MappedVector.l, Irql.KIRQL, EventHandle.l, Status.i
Protected.UNICODE_STRING uniNameString, uniDOSString, EventName
SetPoolMode(#Pool_Auto) ; Автоматический выбор типа памяти в зависимости от IRQL.
DbgPrint("Load Driver")
RtlInitUnicodeString(@uniNameString, ?Device)
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
Status = IoCreateDevice(*DriverObject,SizeOf(LOCAL_DEVICE_INFO),@uniNameString,
#FILE_DEVICE_UNKNOWN,0,#True,@*DeviceObject)
If Status = #STATUS_SUCCESS
*DeviceExtension = *DeviceObject\DeviceExtension
Status = IoCreateSymbolicLink(@uniDOSString, @uniNameString);
If Status = #STATUS_SUCCESS
*DeviceExtension\Level = 7
*DeviceExtension\Vector = *DeviceExtension\Level
MappedVector = HalGetInterruptVector(#Isa,0,*DeviceExtension\Level,
*DeviceExtension\Vector,@Irql,
@*DeviceExtension\Affinity)
IoInitializeDpcRequest(*DeviceObject, @DpcRoutine())
Status = IoConnectInterrupt(@*DeviceExtension\InterruptObject,@Isr(),
*DeviceObject,#Null,MappedVector,Irql,Irql,
#Latched,#False,*DeviceExtension\Affinity,#False)
If Status = #STATUS_SUCCESS
; Enable Parallel Port IRQ's
WRITE_PORT_UCHAR(#CONTROL, READ_PORT_UCHAR(#CONTROL) | $10)
*DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
*DriverObject\MajorFunction[#IRP_MJ_CLOSE] = @CreateDispatch()
*DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
*DriverObject\DriverUnload = @DriverUnload()
RtlInitUnicodeString(@EventName, ?Event)
*DeviceExtension\pEventObject = 0
EndIf
EndIf
EndIf
ProcedureReturn Status
EndProcedure
DataSection
Device:
!du '\Device\pbIntLPT', 0, 0
DosDevices:
!du '\DosDevices\pbIntLPT', 0, 0
Event:
!du '\BaseNamedObjects\SignalEventLPT', 0, 0
EndDataSection
Аналог InpOut32 с поддержкой x86 и x64 систем. Последний нужно подписать, хотя бы тестовой подписью, иначе система его не загрузит. (PB_5.11_x86_DriverPack_v2.2.zip\Examples\Driver\Advanced\DriverIO x86 x64\Source\Driver\).
Спойлер
Код: Выделить всё
Declare DriverEntry(*DriverObject, *RegistryPath)
*A=@DriverEntry()
!jmp [p_A]
IncludePath #PB_Compiler_Home+"DDK\"
XIncludeFile "ntddk.pbi"
XIncludeFile "ntstatus.pbi"
XIncludeFile "ntfunct.pbi"
#IOCTL_READ_PORT_UCHAR = $200
#IOCTL_WRITE_PORT_UCHAR = $400
; Прямая запись в порт.
Procedure.b InPort(Port.u)
Protected Result.b=0
EnableASM
MOV DX, Port
IN al,DX
MOV Result, al
DisableASM
ProcedureReturn Result
EndProcedure
; Прямое чтение из порта.
Procedure OutPort(Port.u, Byte.a)
EnableASM
MOV al, Byte
MOV DX, Port
OUT DX, al
DisableASM
EndProcedure
Procedure DeviceIoControl(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
Protected ntStatus, *Point, *Stack.IO_STACK_LOCATION
*Stack = *pIrp\Tail\Overlay\CurrentStackLocation
inBuffersize = *Stack\Parameters\DeviceIoControl\InputBufferLength
outBuffersize = *Stack\Parameters\DeviceIoControl\OutputBufferLength
CtrlBuff = PeekI(*pIrp\SystemBuffer)
address = CtrlBuff & $FFFF
Byte.a = (CtrlBuff>>16)&255
Code = *Stack\Parameters\DeviceIoControl\IoControlCode
ntStatus = #STATUS_SUCCESS
Select Code
Case #IOCTL_READ_PORT_UCHAR
InByte.b=InPort(address)
PokeB(*pIrp\SystemBuffer, InByte)
*pIrp\IoStatus\Information = 1
Case #IOCTL_WRITE_PORT_UCHAR
OutPort(address, Byte)
*pIrp\IoStatus\Information = 0
Default
ntStatus = #STATUS_UNSUCCESSFUL
*pIrp\IoStatus\Information = 0
EndSelect
*pIrp\IoStatus\Status = ntStatus
IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
ProcedureReturn ntStatus
EndProcedure
Procedure CreateDispatch(*DeviceObject.DEVICE_OBJECT, *pIrp.IRP)
*pIrp\IoStatus\Information = 0
*pIrp\IoStatus\Status = #STATUS_SUCCESS
IoCompleteRequest(*pIrp, #IO_NO_INCREMENT)
ProcedureReturn #STATUS_SUCCESS
EndProcedure
Procedure UnloadDriver(*DriverObject.DRIVER_OBJECT)
Protected uniDOSString.UNICODE_STRING
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
IoDeleteSymbolicLink (@uniDOSString)
IoDeleteDevice(*DriverObject\DeviceObject)
!CALL _PB_EOP ; Освобождение ресурсов.
EndProcedure
Procedure DriverEntry(*DriverObject.DRIVER_OBJECT, *RegistryPath.UNICODE_STRING)
Protected deviceObject.DEVICE_OBJECT
Protected uniNameString.UNICODE_STRING
Protected uniDOSString.UNICODE_STRING
RtlInitUnicodeString(@uniNameString, ?Device)
RtlInitUnicodeString(@uniDOSString, ?DosDevices)
status = IoCreateDevice(*DriverObject, 0, @uniNameString, #FILE_DEVICE_UNKNOWN, 0, #False, @deviceObject)
If status <> #STATUS_SUCCESS
ProcedureReturn status
EndIf
status = IoCreateSymbolicLink(@uniDOSString, @uniNameString)
If status <> #STATUS_SUCCESS
IoDeleteDevice(@deviceObject) ; Мы должны сами убирать "хвосты" в режиме ядра!
ProcedureReturn status
EndIf
*DriverObject\DriverUnload = @UnloadDriver()
*DriverObject\MajorFunction[#IRP_MJ_CREATE] = @CreateDispatch()
*DriverObject\MajorFunction[#IRP_MJ_DEVICE_CONTROL] = @DeviceIoControl()
ProcedureReturn #STATUS_SUCCESS
EndProcedure
;
DataSection
CompilerSelect #PB_Compiler_Processor
CompilerCase #PB_Processor_x86
Device:
!du '\Device\pbdriverio', 0, 0
DosDevices:
!du '\DosDevices\pbdriverio', 0, 0
CompilerCase #PB_Processor_x64
Device:
!du '\Device\pbdriverio_x64', 0, 0
DosDevices:
!du '\DosDevices\pbdriverio_x64', 0, 0
CompilerEndSelect
EndDataSection
AndTer писал(а):А если с нуля начинать... может и правда стоит что то из арм. На будущее так сказать.
Соврешенно верно. Современные МК только кажутся сложными, а как начнешь изучать выясняется что они довольно простые.
Repytw писал(а):К Win7 x64 прикрутить это у меня её не вышло.
Нужен драйвер для x64 и с цифровой подписью.
Repytw писал(а):Новичку ARM??? Чтобы сразу отбить желание?
А вы пробовали?

Или не глядя осуждаете?
Небольшой пример содержащий настройку выхода PC13, конфигурацию таймера на 2 прерывания в секунду и их обработку с инвертированием выхода PC13.
Очень сложный код? Он написан с применением библиотеки SPL. Тоже можно сделать на регистрах и получится как в PIC или AVR.
Спойлер
Код: Выделить всё
#include "stm32f10x_conf.h"
extern uint32_t SystemCoreClock; // В переменной хранится текущая частота ядра МК.
void TIM2_IRQHandler(void) // Функция обработки прерывания от TIM2.
{
// Прерывание по переполнению таймера.
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // Сброс флага прерывания.
GPIOC->ODR ^= GPIO_Pin_13; // Инвертирование вывода PC13.
}
}
void Init(void) // Инициализация периферии.
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // Включение тактирования таймера
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); // и порта GPIOC.
// Настройка порта в/в PC13.
GPIO_InitTypeDef gpio;
gpio.GPIO_Pin = GPIO_Pin_13; // Пин 13.
gpio.GPIO_Mode = GPIO_Mode_Out_PP; // Выход типа push-pull.
gpio.GPIO_Speed = GPIO_Speed_50MHz; // Предельная частота выхода.
GPIO_Init(GPIOC, &gpio); // Конфигурация GPIOC.
// Настройка таймера.
TIM_TimeBaseInitTypeDef Tim;
TIM_TimeBaseStructInit(&Tim); // Настройки таймера по умолчанию.
Tim.TIM_Prescaler = SystemCoreClock / 10000 - 1; // Настройка предделителся чтобы получить частоту 10 КГц.
Tim.TIM_Period = 5000 - 1; // Таймер будет переполняться 10000 / 5000 = 2 раза в секунду.
TIM_TimeBaseInit(TIM2, &Tim); // Инициализация таймера TIM2 с заданными настройками.
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // Разрешение прерываний по переполнению.
NVIC_EnableIRQ(TIM2_IRQn); // Разрешение прерываний от таймера.
TIM_Cmd(TIM2, ENABLE); // Запуск таймера.
}
int main(void)
{
SystemCoreClockUpdate(); // Вычисление текущей частоты ядра.
Init(); // Инициализация периферии.
while(1)
{
}
}
Код для такой платы (используется светодиод на ней).
Спойлер

Ivanoff-iv писал(а):изначально ТС'ом было сказано про "АВР" и "не ардуино"
Может он про другие МК ничего не знает. Зачем изучать устаревшие технологии? Это в дальнейшем вызовет трудности из-за нехватки ресурсов платформы и придется переучиваться.

Зачем зря тратить время на то что устарело?
